Start removing the old build infrastructure for the a.out
[dragonfly.git] / sbin / ldconfig / ldconfig.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1993,1995 Paul Kranenburg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Paul Kranenburg.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1de703da
MD
29 *
30 * $FreeBSD: src/sbin/ldconfig/ldconfig.c,v 1.31.2.3 2001/07/11 23:59:10 obrien Exp $
aa8d5dcb 31 * $DragonFly: src/sbin/ldconfig/ldconfig.c,v 1.5 2004/03/20 16:27:40 drhodus Exp $
984263bc
MD
32 */
33
984263bc
MD
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/mman.h>
38#include <a.out.h>
39#include <ctype.h>
40#include <dirent.h>
41#include <elf-hints.h>
42#include <err.h>
43#include <errno.h>
44#include <fcntl.h>
aa8d5dcb 45#include <sys/link_aout.h>
984263bc
MD
46#include <objformat.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <unistd.h>
51
52#include "ldconfig.h"
53#include "shlib.h"
54#include "support.h"
55
56#if DEBUG
57/* test */
58#undef _PATH_LD_HINTS
59#define _PATH_LD_HINTS "./ld.so.hints"
60#undef _PATH_ELF_HINTS
61#define _PATH_ELF_HINTS "./ld-elf.so.hints"
62#endif
63
64#undef major
65#undef minor
66
67static int verbose;
68static int nostd;
69static int justread;
70static int merge;
71static int rescan;
72static char *hints_file;
73
74struct shlib_list {
75 /* Internal list of shared libraries found */
76 char *name;
77 char *path;
78 int dewey[MAXDEWEY];
79 int ndewey;
80#define major dewey[0]
81#define minor dewey[1]
82 struct shlib_list *next;
83};
84
85static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
86static char *dir_list;
87
9a76cd75
DR
88static int buildhints(void);
89static int dodir(char *, int);
90int dofile(char *, int);
91static void enter(char *, char *, char *, int *, int);
92static void listhints(void);
93static int readhints(void);
94static void usage(void);
984263bc
MD
95
96int
b5744197 97main(int argc, char **argv)
984263bc
MD
98{
99 int i, c;
100 int rval = 0;
984263bc
MD
101 int is_aout;
102
aa8d5dcb
DR
103 is_aout = 0;
104 if (argc > 1 && strcmp(argv[1], "-aout") == 0) {
984263bc 105 is_aout = 1;
aa8d5dcb
DR
106 argc--;
107 argv++;
108 } else if (argc > 1 && strcmp(argv[1], "-elf") == 0) {
109 /* skip over legacy -elf arg */
110 argc--;
111 argv++;
112 }
984263bc
MD
113
114 hints_file = is_aout ? _PATH_LD_HINTS : _PATH_ELF_HINTS;
115 if (argc == 1)
116 rescan = 1;
117 else while((c = getopt(argc, argv, "Rf:imrsv")) != -1) {
118 switch (c) {
119 case 'R':
120 rescan = 1;
121 break;
122 case 'f':
123 hints_file = optarg;
124 break;
125 case 'i':
126 insecure = 1;
127 break;
128 case 'm':
129 merge = 1;
130 break;
131 case 'r':
132 justread = 1;
133 break;
134 case 's':
135 nostd = 1;
136 break;
137 case 'v':
138 verbose = 1;
139 break;
140 default:
141 usage();
142 break;
143 }
144 }
145
146 if (!is_aout) {
147 if (justread)
148 list_elf_hints(hints_file);
149 else
150 update_elf_hints(hints_file, argc - optind,
151 argv + optind, merge || rescan);
152 return 0;
153 }
154
155 /* Here begins the aout libs processing */
156 dir_list = strdup("");
157
158 if (justread || merge || rescan) {
159 if ((rval = readhints()) != 0)
160 return rval;
161 }
162
163 if (!nostd && !merge && !rescan)
164 std_search_path();
165
166 /* Add any directories/files from the command line */
167 if (!justread) {
168 for (i = optind; i < argc; i++) {
169 struct stat stbuf;
170
171 if (stat(argv[i], &stbuf) == -1) {
172 warn("%s", argv[i]);
173 rval = -1;
174 } else if (strcmp(argv[i], "/usr/lib") == 0) {
175 warnx("WARNING! '%s' can not be used", argv[i]);
176 rval = -1;
177 } else {
178 /*
179 * See if this is a directory-containing
180 * file instead of a directory
181 */
182 if (S_ISREG(stbuf.st_mode))
183 rval |= dofile(argv[i], 0);
184 else
185 add_search_path(argv[i]);
186 }
187 }
188 }
189
190 for (i = 0; i < n_search_dirs; i++) {
191 char *cp = concat(dir_list, *dir_list?":":"", search_dirs[i]);
192 free(dir_list);
193 dir_list = cp;
194 }
195
196 if (justread) {
197 listhints();
198 return 0;
199 }
200
201 for (i = 0; i < n_search_dirs; i++)
202 rval |= dodir(search_dirs[i], 1);
203
204 rval |= buildhints();
205
206 return rval;
207}
208
209static void
b5744197 210usage(void)
984263bc
MD
211{
212 fprintf(stderr,
213 "usage: ldconfig [-aout | -elf] [-Rimrsv] [-f hints_file] [dir | file ...]\n");
214 exit(1);
215}
216
217int
b5744197 218dofile(char *fname, int silent)
984263bc
MD
219{
220 FILE *hfp;
221 char buf[MAXPATHLEN];
222 int rval = 0;
223 char *cp, *sp;
224
225 if ((hfp = fopen(fname, "r")) == NULL) {
226 warn("%s", fname);
227 return -1;
228 }
229
230 while (fgets(buf, sizeof(buf), hfp)) {
231 cp = buf;
232 while (isspace(*cp))
233 cp++;
234 if (*cp == '#' || *cp == '\0')
235 continue;
236 sp = cp;
237 while (!isspace(*cp) && *cp != '\0')
238 cp++;
239
240 if (*cp != '\n') {
241 *cp = '\0';
242 warnx("%s: trailing characters ignored", sp);
243 }
244
245 *cp = '\0';
246
247 rval |= dodir(sp, silent);
248 }
249
250 (void)fclose(hfp);
251 return rval;
252}
253
254int
b5744197 255dodir(char *dir, int silent)
984263bc
MD
256{
257 DIR *dd;
258 struct dirent *dp;
259 char name[MAXPATHLEN];
260 int dewey[MAXDEWEY], ndewey;
261
262 if ((dd = opendir(dir)) == NULL) {
263 if (silent && errno == ENOENT) /* Ignore the error */
264 return 0;
265 warn("%s", dir);
266 return -1;
267 }
268
269 while ((dp = readdir(dd)) != NULL) {
270 register int n;
271 register char *cp;
272
273 /* Check for `lib' prefix */
274 if (dp->d_name[0] != 'l' ||
275 dp->d_name[1] != 'i' ||
276 dp->d_name[2] != 'b')
277 continue;
278
279 /* Copy the entry minus prefix */
280 (void)strcpy(name, dp->d_name + 3);
281 n = strlen(name);
282 if (n < 4)
283 continue;
284
285 /* Find ".so." in name */
286 for (cp = name + n - 4; cp > name; --cp) {
287 if (cp[0] == '.' &&
288 cp[1] == 's' &&
289 cp[2] == 'o' &&
290 cp[3] == '.')
291 break;
292 }
293 if (cp <= name)
294 continue;
295
296 *cp = '\0';
297 if (!isdigit(*(cp+4)))
298 continue;
299
300 bzero((caddr_t)dewey, sizeof(dewey));
301 ndewey = getdewey(dewey, cp + 4);
302 if (ndewey < 2)
303 continue;
304 enter(dir, dp->d_name, name, dewey, ndewey);
305 }
306
307 closedir(dd);
308 return 0;
309}
310
311static void
b5744197 312enter(char *dir, char *file, char *name, int *dewey, int ndewey)
984263bc
MD
313{
314 struct shlib_list *shp;
315
316 for (shp = shlib_head; shp; shp = shp->next) {
317 if (strcmp(name, shp->name) != 0 || major != shp->major)
318 continue;
319
320 /* Name matches existing entry */
321 if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
322
323 /* Update this entry with higher versioned lib */
324 if (verbose)
325 printf("Updating lib%s.%d.%d to %s/%s\n",
326 shp->name, shp->major, shp->minor,
327 dir, file);
328
329 free(shp->name);
330 shp->name = strdup(name);
331 free(shp->path);
332 shp->path = concat(dir, "/", file);
333 bcopy(dewey, shp->dewey, sizeof(shp->dewey));
334 shp->ndewey = ndewey;
335 }
336 break;
337 }
338
339 if (shp)
340 /* Name exists: older version or just updated */
341 return;
342
343 /* Allocate new list element */
344 if (verbose)
345 printf("Adding %s/%s\n", dir, file);
346
347 shp = (struct shlib_list *)xmalloc(sizeof *shp);
348 shp->name = strdup(name);
349 shp->path = concat(dir, "/", file);
350 bcopy(dewey, shp->dewey, MAXDEWEY);
351 shp->ndewey = ndewey;
352 shp->next = NULL;
353
354 *shlib_tail = shp;
355 shlib_tail = &shp->next;
356}
357
358
359int
b5744197 360hinthash(char *cp, int vmajor)
984263bc
MD
361{
362 int k = 0;
363
364 while (*cp)
365 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
366
367 k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
368
369 return k;
370}
371
372int
b5744197 373buildhints(void)
984263bc
MD
374{
375 struct hints_header hdr;
376 struct hints_bucket *blist;
377 struct shlib_list *shp;
378 char *strtab;
379 int i, n, str_index = 0;
380 int strtab_sz = 0; /* Total length of strings */
381 int nhints = 0; /* Total number of hints */
382 int fd;
383 char *tmpfile;
384
385 for (shp = shlib_head; shp; shp = shp->next) {
386 strtab_sz += 1 + strlen(shp->name);
387 strtab_sz += 1 + strlen(shp->path);
388 nhints++;
389 }
390
391 /* Fill hints file header */
392 hdr.hh_magic = HH_MAGIC;
393 hdr.hh_version = LD_HINTS_VERSION_2;
394 hdr.hh_nbucket = 1 * nhints;
395 n = hdr.hh_nbucket * sizeof(struct hints_bucket);
396 hdr.hh_hashtab = sizeof(struct hints_header);
397 hdr.hh_strtab = hdr.hh_hashtab + n;
398 hdr.hh_dirlist = strtab_sz;
399 strtab_sz += 1 + strlen(dir_list);
400 hdr.hh_strtab_sz = strtab_sz;
401 hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
402
403 if (verbose)
404 printf("Totals: entries %d, buckets %ld, string size %d\n",
405 nhints, (long)hdr.hh_nbucket, strtab_sz);
406
407 /* Allocate buckets and string table */
408 blist = (struct hints_bucket *)xmalloc(n);
409 bzero((char *)blist, n);
410 for (i = 0; i < hdr.hh_nbucket; i++)
411 /* Empty all buckets */
412 blist[i].hi_next = -1;
413
414 strtab = (char *)xmalloc(strtab_sz);
415
416 /* Enter all */
417 for (shp = shlib_head; shp; shp = shp->next) {
418 struct hints_bucket *bp;
419
420 bp = blist +
421 (hinthash(shp->name, shp->major) % hdr.hh_nbucket);
422
423 if (bp->hi_pathx) {
424 int i;
425
426 for (i = 0; i < hdr.hh_nbucket; i++) {
427 if (blist[i].hi_pathx == 0)
428 break;
429 }
430 if (i == hdr.hh_nbucket) {
431 warnx("bummer!");
432 return -1;
433 }
434 while (bp->hi_next != -1)
435 bp = &blist[bp->hi_next];
436 bp->hi_next = i;
437 bp = blist + i;
438 }
439
440 /* Insert strings in string table */
441 bp->hi_namex = str_index;
442 strcpy(strtab + str_index, shp->name);
443 str_index += 1 + strlen(shp->name);
444
445 bp->hi_pathx = str_index;
446 strcpy(strtab + str_index, shp->path);
447 str_index += 1 + strlen(shp->path);
448
449 /* Copy versions */
450 bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
451 bp->hi_ndewey = shp->ndewey;
452 }
453
454 /* Copy search directories */
455 strcpy(strtab + str_index, dir_list);
456 str_index += 1 + strlen(dir_list);
457
458 /* Sanity check */
459 if (str_index != strtab_sz) {
460 errx(1, "str_index(%d) != strtab_sz(%d)", str_index, strtab_sz);
461 }
462
463 tmpfile = concat(hints_file, ".XXXXXXXXXX", "");
464 umask(0); /* Create with exact permissions */
465 if ((fd = mkstemp(tmpfile)) == -1) {
466 warn("%s", tmpfile);
467 return -1;
468 }
469 fchmod(fd, 0444);
470
471 if (write(fd, &hdr, sizeof(struct hints_header)) !=
472 sizeof(struct hints_header)) {
473 warn("%s", hints_file);
474 return -1;
475 }
476 if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
477 hdr.hh_nbucket * sizeof(struct hints_bucket)) {
478 warn("%s", hints_file);
479 return -1;
480 }
481 if (write(fd, strtab, strtab_sz) != strtab_sz) {
482 warn("%s", hints_file);
483 return -1;
484 }
485 if (close(fd) != 0) {
486 warn("%s", hints_file);
487 return -1;
488 }
489
490 /* Install it */
491 if (unlink(hints_file) != 0 && errno != ENOENT) {
492 warn("%s", hints_file);
493 return -1;
494 }
495
496 if (rename(tmpfile, hints_file) != 0) {
497 warn("%s", hints_file);
498 return -1;
499 }
500
501 return 0;
502}
503
504static int
b5744197 505readhints(void)
984263bc
MD
506{
507 int fd;
508 void *addr;
509 long fsize;
510 long msize;
511 struct hints_header *hdr;
512 struct hints_bucket *blist;
513 char *strtab;
514 struct shlib_list *shp;
515 int i;
516
517 if ((fd = open(hints_file, O_RDONLY, 0)) == -1) {
518 warn("%s", hints_file);
519 return -1;
520 }
521
522 msize = PAGE_SIZE;
523 addr = mmap(0, msize, PROT_READ, MAP_COPY, fd, 0);
524
525 if (addr == MAP_FAILED) {
526 warn("%s", hints_file);
527 return -1;
528 }
529
530 hdr = (struct hints_header *)addr;
531 if (HH_BADMAG(*hdr)) {
532 warnx("%s: bad magic: %lo", hints_file,
533 (unsigned long)hdr->hh_magic);
534 return -1;
535 }
536
537 if (hdr->hh_version != LD_HINTS_VERSION_1 &&
538 hdr->hh_version != LD_HINTS_VERSION_2) {
539 warnx("unsupported version: %ld", (long)hdr->hh_version);
540 return -1;
541 }
542
543 if (hdr->hh_ehints > msize) {
544 fsize = hdr->hh_ehints;
545 munmap(addr, msize);
546 addr = mmap(0, fsize, PROT_READ, MAP_COPY, fd, 0);
547 if (addr == MAP_FAILED) {
548 warn("%s", hints_file);
549 return -1;
550 }
551 hdr = (struct hints_header *)addr;
552 }
553 close(fd);
554
555 blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
556 strtab = (char *)(addr + hdr->hh_strtab);
557
558 if (hdr->hh_version >= LD_HINTS_VERSION_2)
559 add_search_path(strtab + hdr->hh_dirlist);
560 else if (rescan)
561 errx(1, "%s too old and does not contain the search path",
562 hints_file);
563
564 if (rescan)
565 return 0;
566
567 for (i = 0; i < hdr->hh_nbucket; i++) {
568 struct hints_bucket *bp = &blist[i];
569
570 /* Sanity check */
571 if (bp->hi_namex >= hdr->hh_strtab_sz) {
572 warnx("bad name index: %#x", bp->hi_namex);
573 return -1;
574 }
575 if (bp->hi_pathx >= hdr->hh_strtab_sz) {
576 warnx("bad path index: %#x", bp->hi_pathx);
577 return -1;
578 }
579
580 /* Allocate new list element */
581 shp = (struct shlib_list *)xmalloc(sizeof *shp);
582 shp->name = strdup(strtab + bp->hi_namex);
583 shp->path = strdup(strtab + bp->hi_pathx);
584 bcopy(bp->hi_dewey, shp->dewey, sizeof(shp->dewey));
585 shp->ndewey = bp->hi_ndewey;
586 shp->next = NULL;
587
588 *shlib_tail = shp;
589 shlib_tail = &shp->next;
590 }
591
592 return 0;
593}
594
595static void
b5744197 596listhints(void)
984263bc
MD
597{
598 struct shlib_list *shp;
599 int i;
600
601 printf("%s:\n", hints_file);
602 printf("\tsearch directories: %s\n", dir_list);
603
604 for (i = 0, shp = shlib_head; shp; i++, shp = shp->next)
605 printf("\t%d:-l%s.%d.%d => %s\n",
606 i, shp->name, shp->major, shp->minor, shp->path);
607
608 return;
609}