1 /* $NetBSD: ldconfig.c,v 1.45 2009/03/17 00:52:47 lukem Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: ldconfig.c,v 1.45 2009/03/17 00:52:47 lukem Exp $");
38 #include <sys/param.h>
39 #include <sys/types.h>
44 #include <sys/exec_aout.h>
55 #include <link_aout.h>
60 #define _PATH_LD_SO_CONF "/etc/ld.so.conf"
72 /* Internal list of shared libraries found */
77 #define major dewey[0]
78 #define minor dewey[1]
79 struct shlib_list
*next
;
82 static struct shlib_list
*shlib_head
= NULL
, **shlib_tail
= &shlib_head
;
83 static char *dir_list
;
85 static void enter(char *, char *, char *, int *, int);
86 static int dodir(char *, int, int);
87 static int do_conf(void);
88 static int buildhints(void);
89 static int readhints(void);
90 static void listhints(void);
91 static int hinthash(char *, int, int);
94 main(int argc
, char *argv
[])
99 while ((c
= getopt(argc
, argv
, "cmrsSv")) != -1) {
121 errx(1, "usage: %s [-c][-m][-r][-s][-S][-v][dir ...]",
127 dir_list
= xmalloc(1);
130 if (justread
|| merge
) {
131 if ((rval
= readhints()) != 0)
139 if (!nostd
&& !merge
)
142 for (i
= 0; i
< n_search_dirs
; i
++)
143 rval
|= dodir(search_dirs
[i
], 1, 0);
145 if (!noconf
&& !merge
)
148 for (i
= optind
; i
< argc
; i
++) {
149 rval
|= dodir(argv
[i
], 0, 1);
152 rval
|= buildhints();
168 aout_conf
= xmalloc(sizeof(_PATH_EMUL_AOUT
) +
169 strlen(_PATH_LD_SO_CONF
));
170 strcpy(aout_conf
, _PATH_EMUL_AOUT
);
171 strcat(aout_conf
, _PATH_LD_SO_CONF
);
172 if ((conf
= fopen(aout_conf
, "r")) == NULL
) {
174 warnx("can't open `%s'", aout_conf
);
180 if ((conf
= fopen(_PATH_LD_SO_CONF
, "r")) == NULL
) {
182 warnx("can't open `%s'", _PATH_LD_SO_CONF
);
188 while ((line
= fgetln(conf
, &len
)) != NULL
) {
192 if (line
[len
-1] == '\n') {
195 cline
= xmalloc(len
+1);
196 memcpy(cline
, line
, len
);
201 while (isblank(*line
)) { line
++; len
--; }
202 if ((c
= strchr(line
, '#')) == NULL
)
204 while (--c
>= line
&& isblank(*c
)) continue;
207 rval
|= dodir(line
, 0, 1);
222 dodir(char *dir
, int silent
, int update_dir_list
)
226 char name
[MAXPATHLEN
];
227 int dewey
[MAXDEWEY
], ndewey
;
229 if ((dd
= opendir(dir
)) == NULL
) {
230 /* /emul/aout directories are allowed to not exist.
232 if (!strncmp(dir
, _PATH_EMUL_AOUT
, sizeof(_PATH_EMUL_AOUT
)-1))
234 if (!silent
|| errno
!= ENOENT
)
239 if (update_dir_list
) {
240 /* Check for duplicates? */
241 char *cp
= concat(dir_list
, *dir_list
?":":"", dir
);
246 while ((dp
= readdir(dd
)) != NULL
) {
252 /* Check for `lib' prefix */
253 if (dp
->d_name
[0] != 'l' ||
254 dp
->d_name
[1] != 'i' ||
255 dp
->d_name
[2] != 'b')
258 /* Copy the entry minus prefix */
259 (void)strcpy(name
, dp
->d_name
+ 3);
264 /* Find ".so." in name */
265 for (cp
= name
+ n
- 4; cp
> name
; --cp
) {
275 path
= concat(dir
, "/", dp
->d_name
);
276 fp
= fopen(path
, "r");
280 n
= fread(&ex
, 1, sizeof(ex
), fp
);
283 || N_GETMAGIC(ex
) != ZMAGIC
284 || (N_GETFLAG(ex
) & EX_DYNAMIC
) == 0)
288 if (!isdigit((unsigned char)*(cp
+4)))
291 memset(dewey
, 0, sizeof(dewey
));
292 ndewey
= getdewey(dewey
, cp
+ 4);
293 enter(dir
, dp
->d_name
, name
, dewey
, ndewey
);
302 enter(char *dir
, char *file
, char *name
, int dewey
[], int ndewey
)
304 struct shlib_list
*shp
;
306 for (shp
= shlib_head
; shp
; shp
= shp
->next
) {
307 if (strcmp(name
, shp
->name
) != 0 || major
!= shp
->major
)
310 /* Name matches existing entry */
311 if (cmpndewey(dewey
, ndewey
, shp
->dewey
, shp
->ndewey
) > 0) {
313 /* Update this entry with higher versioned lib */
315 printf("Updating lib%s.%d.%d to %s/%s\n",
316 shp
->name
, shp
->major
, shp
->minor
,
320 shp
->name
= strdup(name
);
322 shp
->path
= concat(dir
, "/", file
);
323 memcpy(shp
->dewey
, dewey
, sizeof(shp
->dewey
));
324 shp
->ndewey
= ndewey
;
330 /* Name exists: older version or just updated */
333 /* Allocate new list element */
335 printf("Adding %s/%s\n", dir
, file
);
337 shp
= (struct shlib_list
*)xmalloc(sizeof *shp
);
338 shp
->name
= strdup(name
);
339 shp
->path
= concat(dir
, "/", file
);
340 memcpy(shp
->dewey
, dewey
, sizeof(shp
->dewey
));
341 shp
->ndewey
= ndewey
;
345 shlib_tail
= &shp
->next
;
351 #undef _PATH_LD_HINTS
352 #define _PATH_LD_HINTS "./ld.so.hints"
355 /* XXX - should be a common function with rtld.c */
357 hinthash(char *cp
, int vmajor
, int vminor
)
362 k
= (((k
<< 1) + (k
>> 14)) ^ (*cp
++)) & 0x3fff;
364 k
= (((k
<< 1) + (k
>> 14)) ^ (vmajor
*257)) & 0x3fff;
366 k
= (((k
<< 1) + (k
>> 14)) ^ (vminor
*167)) & 0x3fff;
375 struct hints_header hdr
;
376 struct hints_bucket
*blist
;
377 struct shlib_list
*shp
;
379 int i
, n
, str_index
= 0;
380 int strtab_sz
= 0; /* Total length of strings */
381 int nhints
= 0; /* Total number of hints */
385 for (shp
= shlib_head
; shp
; shp
= shp
->next
) {
386 strtab_sz
+= 1 + strlen(shp
->name
);
387 strtab_sz
+= 1 + strlen(shp
->path
);
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
;
404 printf("Totals: entries %d, buckets %ld, string size %d\n",
405 nhints
, hdr
.hh_nbucket
, strtab_sz
);
407 /* Allocate buckets and string table */
408 blist
= (struct hints_bucket
*)xmalloc(n
);
410 for (i
= 0; i
< hdr
.hh_nbucket
; i
++)
411 /* Empty all buckets */
412 blist
[i
].hi_next
= -1;
414 strtab
= (char *)xmalloc(strtab_sz
);
417 for (shp
= shlib_head
; shp
; shp
= shp
->next
) {
418 struct hints_bucket
*bp
;
421 (hinthash(shp
->name
, shp
->major
, shp
->minor
) % hdr
.hh_nbucket
);
424 for (i
= 0; i
< hdr
.hh_nbucket
; i
++) {
425 if (blist
[i
].hi_pathx
== 0)
428 if (i
== hdr
.hh_nbucket
) {
432 while (bp
->hi_next
!= -1)
433 bp
= &blist
[bp
->hi_next
];
438 /* Insert strings in string table */
439 bp
->hi_namex
= str_index
;
440 strcpy(strtab
+ str_index
, shp
->name
);
441 str_index
+= 1 + strlen(shp
->name
);
443 bp
->hi_pathx
= str_index
;
444 strcpy(strtab
+ str_index
, shp
->path
);
445 str_index
+= 1 + strlen(shp
->path
);
448 memcpy(bp
->hi_dewey
, shp
->dewey
, sizeof(bp
->hi_dewey
));
449 bp
->hi_ndewey
= shp
->ndewey
;
452 /* Copy search directories */
453 strcpy(strtab
+ str_index
, dir_list
);
454 str_index
+= 1 + strlen(dir_list
);
457 if (str_index
!= strtab_sz
) {
458 errx(1, "str_index(%d) != strtab_sz(%d)", str_index
, strtab_sz
);
461 tempfile
= concat(_PATH_LD_HINTS
, ".XXXXXX", "");
462 if ((fd
= mkstemp(tempfile
)) == -1) {
463 warn("%s", tempfile
);
467 if (write(fd
, &hdr
, sizeof(struct hints_header
)) !=
468 sizeof(struct hints_header
)) {
469 warn("%s", _PATH_LD_HINTS
);
472 if ((size_t)write(fd
, blist
, hdr
.hh_nbucket
* sizeof(struct hints_bucket
)) !=
473 hdr
.hh_nbucket
* sizeof(struct hints_bucket
)) {
474 warn("%s", _PATH_LD_HINTS
);
477 if (write(fd
, strtab
, strtab_sz
) != strtab_sz
) {
478 warn("%s", _PATH_LD_HINTS
);
481 if (fchmod(fd
, 0444) == -1) {
482 warn("%s", _PATH_LD_HINTS
);
485 if (close(fd
) != 0) {
486 warn("%s", _PATH_LD_HINTS
);
491 if (unlink(_PATH_LD_HINTS
) != 0 && errno
!= ENOENT
) {
492 warn("%s", _PATH_LD_HINTS
);
496 if (rename(tempfile
, _PATH_LD_HINTS
) != 0) {
497 warn("%s", _PATH_LD_HINTS
);
514 void *addr
= (void *) -1;
516 struct hints_header
*hdr
;
517 struct hints_bucket
*blist
;
519 struct shlib_list
*shp
;
524 if ((fd
= open(_PATH_LD_HINTS
, O_RDONLY
, 0)) == -1) {
525 warn("%s", _PATH_LD_HINTS
);
529 if (fstat(fd
, &st
) == -1) {
530 warn("%s", _PATH_LD_HINTS
);
534 msize
= (size_t)st
.st_size
;
535 if (msize
< sizeof(*hdr
)) {
536 warnx("%s: File too short", _PATH_LD_HINTS
);
540 addr
= mmap(0, msize
, PROT_READ
, MAP_FILE
|MAP_PRIVATE
, fd
, 0);
542 if (addr
== (void *)-1) {
543 warn("%s", _PATH_LD_HINTS
);
547 hdr
= (struct hints_header
*)addr
;
548 if (HH_BADMAG(*hdr
)) {
549 warnx("%s: Bad magic: %lo",
550 _PATH_LD_HINTS
, hdr
->hh_magic
);
554 if (hdr
->hh_version
!= LD_HINTS_VERSION_2
) {
555 warnx("Unsupported version: %ld", hdr
->hh_version
);
560 blist
= (struct hints_bucket
*)((char *)addr
+ hdr
->hh_hashtab
);
561 strtab
= ((char *)addr
+ hdr
->hh_strtab
);
563 for (i
= 0; i
< hdr
->hh_nbucket
; i
++) {
564 struct hints_bucket
*bp
= &blist
[i
];
567 if (bp
->hi_namex
>= hdr
->hh_strtab_sz
) {
568 warnx("Bad name index: %#x", bp
->hi_namex
);
571 if (bp
->hi_pathx
>= hdr
->hh_strtab_sz
) {
572 warnx("Bad path index: %#x", bp
->hi_pathx
);
576 /* Allocate new list element */
577 shp
= (struct shlib_list
*)xmalloc(sizeof *shp
);
578 shp
->name
= strdup(strtab
+ bp
->hi_namex
);
579 shp
->path
= strdup(strtab
+ bp
->hi_pathx
);
580 memcpy(shp
->dewey
, bp
->hi_dewey
, sizeof(shp
->dewey
));
581 shp
->ndewey
= bp
->hi_ndewey
;
585 shlib_tail
= &shp
->next
;
587 dir_list
= strdup(strtab
+ hdr
->hh_dirlist
);
594 if (addr
!= (void *)-1)
603 struct shlib_list
*shp
;
606 printf("%s:\n", _PATH_LD_HINTS
);
607 printf("\tsearch directories: %s\n", dir_list
);
609 for (i
= 0, shp
= shlib_head
; shp
; i
++, shp
= shp
->next
)
610 printf("\t%d:-l%s.%d.%d => %s\n",
611 i
, shp
->name
, shp
->major
, shp
->minor
, shp
->path
);