OSDN Git Service

fix ld.so.cache handling on no-mmu setups
[uclinux-h8/uclibc-ng.git] / utils / ldconfig.c
1 /*
2  * ldconfig - update shared library symlinks
3  *
4  * usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...
5  *        ldconfig -l [-Dv] lib ...
6  *        ldconfig -p
7  *        -D: debug mode, don't update links
8  *        -v: verbose mode, print things as we go
9  *        -q: quiet mode, don't print warnings
10  *        -n: don't process standard directories
11  *        -N: don't update the library cache
12  *        -X: don't update the library links
13  *        -l: library mode, manually link libraries
14  *        -p: print the current library cache
15  *        -f conf: use conf instead of /etc/ld.so.conf
16  *        -C cache: use cache instead of /etc/ld.so.cache
17  *        -r root: first, do a chroot to the indicated directory
18  *        dir ...: directories to process
19  *        lib ...: libraries to link
20  *
21  * Copyright 1994-2000 David Engel and Mitch D'Souza
22  *
23  * This program may be used for any purpose as long as this
24  * copyright notice is kept.
25  *
26  * 2005/09/16: Dan Howell (modified for cross-development)
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <getopt.h>
35 #include <dirent.h>
36 #include <unistd.h>
37 #include <link.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #include "bswap.h"
43 #include "dl-defs.h"
44
45 #define BUFFER_SIZE 4096
46
47 struct exec
48 {
49   unsigned long a_info;         /* Use macros N_MAGIC, etc for access */
50   unsigned a_text;              /* length of text, in bytes */
51   unsigned a_data;              /* length of data, in bytes */
52   unsigned a_bss;               /* length of uninitialized data area for file, in bytes */
53   unsigned a_syms;              /* length of symbol table data in file, in bytes */
54   unsigned a_entry;             /* start address */
55   unsigned a_trsize;            /* length of relocation info for text, in bytes */
56   unsigned a_drsize;            /* length of relocation info for data, in bytes */
57 };
58
59 #if !defined (N_MAGIC)
60 #define N_MAGIC(exec) ((exec).a_info & 0xffff)
61 #endif
62 #define N_MAGIC_SWAP(exec) (bswap_32((exec).a_info) & 0xffff)
63 /* Code indicating object file or impure executable.  */
64 #define OMAGIC 0407
65 /* Code indicating pure executable.  */
66 #define NMAGIC 0410
67 /* Code indicating demand-paged executable.  */
68 #define ZMAGIC 0413
69 /* This indicates a demand-paged executable with the header in the text. 
70    The first page is unmapped to help trap NULL pointer references */
71 #define QMAGIC 0314
72 /* Code indicating core file.  */
73 #define CMAGIC 0421
74
75 char *___strtok = NULL;
76
77 /* For SunOS */
78 #ifndef PATH_MAX
79 #include <limits.h>
80 #define PATH_MAX _POSIX_PATH_MAX
81 #endif
82
83 /* For SunOS */
84 #ifndef N_MAGIC
85 #define N_MAGIC(exec) ((exec).a_magic & 0xffff)
86 #endif
87
88 #define EXIT_OK    0
89 #define EXIT_FATAL 128
90
91 char *prog = NULL;
92 int debug = 0;                  /* debug mode */
93 int verbose = 0;                /* verbose mode */
94 int libmode = 0;                /* library mode */
95 int nolinks = 0;                /* don't update links */
96 int nocache = 0;                /* don't build cache */
97 void cache_print(void);
98 void cache_write(void);
99 void cache_dolib(const char *dir, const char *so, int libtype);
100 #ifdef __LDSO_CACHE_SUPPORT__
101 char *conffile = LDSO_CONF;     /* default conf file */
102 char *cachefile = LDSO_CACHE;   /* default cache file */
103 #endif
104 char *chroot_dir = NULL;
105 int byteswap = 0;
106
107 struct needed_tab
108 {
109   char *soname;
110   int type;
111 };
112
113 struct needed_tab needed_tab[] = {
114   { "libc.so.0",    LIB_ELF_LIBC0 },
115   { "libm.so.0",    LIB_ELF_LIBC0 },
116   { "libdl.so.0",   LIB_ELF_LIBC0 },
117   { "libc.so.5",    LIB_ELF_LIBC5 },
118   { "libm.so.5",    LIB_ELF_LIBC5 },
119   { "libdl.so.1",   LIB_ELF_LIBC5 },
120   { "libc.so.6",    LIB_ELF_LIBC6 },
121   { "libm.so.6",    LIB_ELF_LIBC6 },
122   { "libdl.so.2",   LIB_ELF_LIBC6 },
123   { NULL,           LIB_ELF }
124 };
125
126 extern char *chroot_realpath(const char *chroot, const char *path, char resolved_path[]);
127
128
129 /* These two are used internally -- you shouldn't need to use them */
130 static void verror_msg(const char *s, va_list p)
131 {
132         fflush(stdout);
133         fprintf(stderr, "%s: ", prog);
134         vfprintf(stderr, s, p);
135 }
136
137 static void warnx(const char *s, ...)
138 {
139         va_list p;
140
141         va_start(p, s);
142         verror_msg(s, p);
143         va_end(p);
144         fprintf(stderr, "\n");
145 }
146
147 static void err(int errnum, const char *s, ...)
148 {
149         va_list p;
150
151         va_start(p, s);
152         verror_msg(s, p);
153         va_end(p);
154         fprintf(stderr, "\n");
155         exit(errnum);
156 }
157
158 static void vperror_msg(const char *s, va_list p)
159 {
160         int err = errno;
161
162         if (s == 0)
163                 s = "";
164         verror_msg(s, p);
165         if (*s)
166                 s = ": ";
167         fprintf(stderr, "%s%s\n", s, strerror(err));
168 }
169
170 static void warn(const char *s, ...)
171 {
172         va_list p;
173
174         va_start(p, s);
175         vperror_msg(s, p);
176         va_end(p);
177 }
178
179 static void *xmalloc(size_t size)
180 {
181     void *ptr;
182     if ((ptr = malloc(size)) == NULL)
183         err(EXIT_FATAL,"out of memory");
184     return ptr;
185 }
186
187 static char *xstrdup(const char *str)
188 {
189     char *ptr;
190     if ((ptr = strdup(str)) == NULL)
191         err(EXIT_FATAL,"out of memory");
192     return ptr;
193 }
194
195
196 #undef __ELF_NATIVE_CLASS
197 #undef readsonameXX
198 #define readsonameXX readsoname32
199 #define __ELF_NATIVE_CLASS 32
200 #include "readsoname2.c"
201
202 #undef __ELF_NATIVE_CLASS
203 #undef readsonameXX
204 #define readsonameXX readsoname64
205 #define __ELF_NATIVE_CLASS 64
206 #include "readsoname2.c"
207
208 char *readsoname(char *name, FILE *infile, int expected_type, 
209                  int *type, int elfclass)
210 {
211   char *res;
212
213   if (elfclass == ELFCLASS32)
214     res = readsoname32(name, infile, expected_type, type);
215   else
216   {
217     res = readsoname64(name, infile, expected_type, type);
218 #if 0
219     *type |= LIB_ELF64;
220 #endif
221   }
222
223   return res;
224 }
225
226
227
228 /* If shared library, return a malloced copy of the soname and set the
229    type, else return NULL.
230
231    expected_type should be either LIB_ANY or one of the following:-
232    LIB_DLL
233    LIB_ELF
234    LIB_ELF_LIBC5
235    LIB_ELF_LIBC6
236
237    If the lib is ELF and we can not deduce the type the type will
238    be set based on expected_type.
239
240    If the expected, actual/deduced types missmatch we display a warning
241    and use the actual/deduced type.
242 */
243 char *is_shlib(const char *dir, const char *name, int *type,
244         int *islink, int expected_type)
245 {
246     char *good = NULL;
247     char *cp, *cp2;
248     FILE *file;
249     struct exec exec;
250     ElfW(Ehdr) *elf_hdr;
251     struct stat statbuf;
252     char buff[BUFFER_SIZE];
253     char real[BUFFER_SIZE];
254     static int byteswapflag = -1;       /* start with byte-order unknown */
255
256     /* see if name is of the form *.so* */
257     if (name[strlen(name)-1] != '~' && (cp = strstr(name, ".so")))
258     {
259         /* find the start of the Vminor part, if any */
260         if (cp[3] == '.' && (cp2 = strchr(cp + 4, '.')))
261             cp = cp2;
262         else
263             cp = cp + strlen(cp);
264
265         /* construct the full path name */
266         sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ?
267                 "/" : "", name);
268
269         /* get real path in case of chroot */
270         if (!chroot_realpath(chroot_dir, buff, real))
271             warn("can't resolve %s in chroot %s", buff, chroot_dir);
272
273         /* first, make sure it's a regular file */
274         if (lstat(real, &statbuf))
275             warn("skipping %s", buff);
276         else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
277             warnx("%s is not a regular file or symlink, skipping", buff);
278         else
279         {
280             /* is it a regular file or a symlink */
281             *islink = S_ISLNK(statbuf.st_mode);
282
283             /* then try opening it */
284             if (!(file = fopen(real, "rb")))
285                 warn("skipping %s", buff);
286             else
287             {
288                 /* now make sure it's a shared library */
289                 if (fread(&exec, sizeof exec, 1, file) < 1)
290                     warnx("can't read header from %s, skipping", buff);
291                 else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
292                          N_MAGIC_SWAP(exec) != ZMAGIC && N_MAGIC_SWAP(exec) != QMAGIC)
293                 {
294                     elf_hdr = (ElfW(Ehdr) *) &exec;
295                     if (elf_hdr->e_ident[0] != 0x7f ||
296                             strncmp(&elf_hdr->e_ident[1], "ELF",3) != 0)
297                     {
298                         /* silently ignore linker scripts */
299                         if (strncmp((char *)&exec, "/* GNU ld", 9) != 0)
300                             warnx("%s is not a shared library, skipping", buff);
301                     }
302                     else
303                     {
304                         /* always call readsoname to update type */
305                         if(expected_type == LIB_DLL) {
306                             warnx("%s is not an a.out library, it's ELF!", buff);
307                             expected_type=LIB_ANY;
308                         }
309                         *type = LIB_ELF;
310                         good = readsoname(buff, file, expected_type, type, 
311                                 elf_hdr->e_ident[EI_CLASS]);
312                         if (byteswapflag == -1)
313                             /* byte-order detected */
314                             byteswapflag = byteswap;
315                         if (good == NULL || *islink)
316                         {
317                             if (good != NULL)
318                                 free(good);
319                             good = xstrdup(name);
320                         }
321                         else
322                         {
323                             /* if the soname does not match the filename,
324                                issue a warning, but only in debug mode. */
325                             int len = strlen(good);
326                             if (debug && (strncmp(good, name, len) != 0 ||
327                                         (name[len] != '\0' && name[len] != '.')))
328                                 warnx("%s has inconsistent soname (%s)", buff, good);
329                         }
330                     }
331                 }
332                 else
333                 {
334                     /* Determine byte-order */
335                     byteswap = (N_MAGIC(exec) == ZMAGIC || N_MAGIC(exec) == QMAGIC) ? 0 : 1;
336                     if (byteswapflag == -1)
337                         /* byte-order detected */
338                         byteswapflag = byteswap;
339
340                     if (*islink)
341                         good = xstrdup(name);
342                     else
343                     {
344                         good = xmalloc(cp - name + 1);
345                         strncpy(good, name, cp - name);
346                         good[cp - name] = '\0';
347                     }
348                     if(expected_type != LIB_ANY && expected_type != LIB_DLL)
349                     {
350                         warnx("%s is not an ELF library, its an a.out DLL!", buff);
351                         expected_type=LIB_ANY;
352                     }
353
354                     *type = LIB_DLL;
355                 }
356                 fclose(file);
357
358                 if (byteswapflag >= 0 && byteswap != byteswapflag)
359                 {
360                     byteswapflag = -2;
361                     warnx("mixed byte-order detected, using host byte-order...");
362                 }
363                 if (byteswapflag == -2)
364                     byteswap = 0;
365             }
366         }
367     }
368
369     return good;
370 }
371
372 /* update the symlink to new library */
373 void link_shlib(const char *dir, const char *file, const char *so)
374 {
375     int change = 1;
376     char libname[BUFFER_SIZE];
377     char linkname[BUFFER_SIZE];
378     char reallibname[BUFFER_SIZE];
379     char reallinkname[BUFFER_SIZE];
380     struct stat libstat;
381     struct stat linkstat;
382
383     /* construct the full path names */
384     sprintf(libname, "%s/%s", dir, file);
385     sprintf(linkname, "%s/%s", dir, so);
386     if (!chroot_realpath(chroot_dir, libname, reallibname))
387         warn("can't resolve %s in chroot %s", libname, chroot_dir);
388     if (!chroot_realpath(chroot_dir, linkname, reallinkname))
389         warn("can't resolve %s in chroot %s", linkname, chroot_dir);
390
391     /* see if a link already exists */
392     if (!stat(reallinkname, &linkstat))
393     {
394         /* now see if it's the one we want */
395         if (stat(reallibname, &libstat))
396             warn("can't stat %s", libname);
397         else if (libstat.st_dev == linkstat.st_dev &&
398                 libstat.st_ino == linkstat.st_ino)
399             change = 0;
400     }
401
402     /* then update the link, if required */
403     if (change > 0 && !nolinks)
404     {
405         if (!lstat(reallinkname, &linkstat))
406         {
407             if (!S_ISLNK(linkstat.st_mode))
408             {
409                 warnx("%s is not a symlink", linkname);
410                 change = -1;
411             }
412             else if (remove(reallinkname))
413             {
414                 warn("can't unlink %s", linkname);
415                 change = -1;
416             }
417         }
418         if (change > 0)
419         {
420             if (symlink(file, reallinkname))
421             {
422                 warn("can't link %s to %s", linkname, file);
423                 change = -1;
424             }
425         }
426     }
427
428     /* some people like to know what we're doing */
429     if (verbose > 0)
430         printf("\t%s => %s%s\n", so, file,
431                 change < 0 ? " (SKIPPED)" :
432                 (change > 0 ? " (changed)" : ""));
433
434     return;
435 }
436
437 /* figure out which library is greater */
438 int libcmp(char *p1, char *p2)
439 {
440     while (*p1)
441     {
442         if (isdigit(*p1) && isdigit(*p2))
443         {
444             /* must compare this numerically */
445             int v1, v2;
446             v1 = strtoul(p1, &p1, 10);
447             v2 = strtoul(p2, &p2, 10);
448             if (v1 != v2)
449                 return v1 - v2;
450         }
451         else if (isdigit(*p1) && !isdigit(*p2))
452             return 1;
453         else if (!isdigit(*p1) && isdigit(*p2))
454             return -1;
455         else if (*p1 != *p2)
456             return *p1 - *p2;
457         else
458             p1++, p2++;
459     }
460
461     return *p1 - *p2;
462 }
463
464 struct lib
465 {
466     char *so;                   /* soname of a library */
467     char *name;                 /* name of a library */
468     int libtype;                /* type of a library */
469     int islink;                 /* is it a symlink */
470     struct lib *next;           /* next library in list */
471 };
472
473 /* update all shared library links in a directory */
474 void scan_dir(const char *rawname)
475 {
476     DIR *dir;
477     const char *name;
478     struct dirent *ent;
479     char *so, *path, *path_n;
480     struct lib *lp, *libs = NULL;
481     int i, libtype, islink, expected_type = LIB_ANY;
482     char realname[BUFFER_SIZE];
483
484     /* We need a writable copy of this string */
485     path = strdup(rawname);
486     if (!path) {
487         err(EXIT_FATAL, "Out of memory!\n");
488     }
489     /* Eliminate all double //s */
490     path_n=path;
491     while((path_n=strstr(path_n, "//"))) {
492         i = strlen(path_n);
493         memmove(path_n, path_n+1, i-1);
494         *(path_n + i - 1)='\0';
495     }
496     name = path;
497
498 #if 0
499     char *t;
500     /* Check for an embedded expected type */
501     t=strrchr(name, '=');
502     if( t )
503     {
504         *t++ = '\0'; /* Skip = char */
505         if(strcasecmp(t, "libc4") == 0)
506         {
507             expected_type = LIB_DLL;
508         } 
509         else
510         {
511             if(strcasecmp(t, "libc5") == 0)
512             {
513                 expected_type = LIB_ELF_LIBC5; 
514             }
515             else
516             {
517                 if(strcasecmp(t, "libc6") == 0)
518                 {
519                     expected_type = LIB_ELF_LIBC6;
520                 }
521                 else 
522                 {
523                     if(strcasecmp(t, "libc0") == 0)
524                     {
525                         expected_type = LIB_ELF_LIBC0;
526                     }
527                     else
528                     {
529                         warnx("Unknown type field '%s' for dir '%s' - ignored", t, name);
530                         expected_type = LIB_ANY;
531                     }
532                 }
533             }
534         }
535     }
536 #endif
537
538     /* let 'em know what's going on */
539     if (verbose > 0)
540         printf("%s:\n", name);
541
542     /* get real path in case of chroot */
543     if (!chroot_realpath(chroot_dir, name, realname))
544         warn("can't resolve %s in chroot %s", name, chroot_dir);
545
546     /* if we can't open it, we can't do anything */
547     if ((dir = opendir(realname)) == NULL)
548     {
549         warn("skipping %s", name);
550         free(path);
551         return;
552     }
553
554     /* yes, we have to look at every single file */
555     while ((ent = readdir(dir)) != NULL)
556     {
557         /* if it's not a shared library, don't bother */
558         if ((so = is_shlib(name, ent->d_name, &libtype, &islink, expected_type)) == NULL)
559             continue;
560
561         /* have we already seen one with the same so name? */
562         for (lp = libs; lp; lp = lp->next)
563         {
564             if (strcmp(so, lp->so) == 0)
565             {
566                 /* we have, which one do we want to use? */
567                 if ((!islink && lp->islink) ||
568                         (islink == lp->islink && 
569                          libcmp(ent->d_name, lp->name) > 0))
570                 {
571                     /* let's use the new one */
572                     free(lp->name);
573                     lp->name = xstrdup(ent->d_name);
574                     lp->libtype = libtype;
575                     lp->islink = islink;
576                 } 
577                 break;
578             }
579         }
580
581         /* congratulations, you're the first one we've seen */
582         if (!lp)
583         {
584             lp = xmalloc(sizeof *lp);
585             lp->so = xstrdup(so);
586             lp->name = xstrdup(ent->d_name);
587             lp->libtype = libtype;
588             lp->islink = islink;
589             lp->next = libs;
590             libs = lp;
591         }
592
593         free(so);
594     }
595
596     /* don't need this any more */
597     closedir(dir);
598
599     /* now we have all the latest libs, update the links */
600     for (lp = libs; lp; lp = lp->next)
601     {
602         if (!lp->islink)
603             link_shlib(name, lp->name, lp->so);
604         if (!nocache)
605             cache_dolib(name, lp->so, lp->libtype);
606     }
607
608     /* always try to clean up after ourselves */
609     while (libs)
610     {
611         lp = libs->next;
612         free(libs->so);
613         free(libs->name);
614         free(libs);
615         libs = lp;
616     }
617
618     free(path);
619     return;
620 }
621
622 #ifndef __LDSO_CACHE_SUPPORT__
623 void cache_print(void)
624 {
625     printf("Library cache disabled\n");
626 }
627 void cache_dolib(const char *dir, const char *so, int libtype)
628 {
629     return;
630 }
631 void cache_write(void)
632 {
633     return;
634 }
635 #else
636 /* return the list of system-specific directories */
637 char *get_extpath(void)
638 {
639     char *res = NULL, *cp;
640     FILE *file;
641     struct stat stat;
642     char realconffile[BUFFER_SIZE];
643
644     if (!chroot_realpath(chroot_dir, conffile, realconffile))
645         return NULL;
646
647     if ((file = fopen(realconffile, "r")) != NULL)
648     {
649         fstat(fileno(file), &stat);
650         res = xmalloc(stat.st_size + 1);
651         fread(res, 1, stat.st_size, file);
652         fclose(file);
653         res[stat.st_size] = '\0';
654
655         /* convert comments fo spaces */
656         for (cp = res; *cp; /*nada*/) {
657             if (*cp == '#') {
658                 do
659                     *cp++ = ' ';
660                 while (*cp && *cp != '\n');
661             } else {
662                 cp++;
663             }
664         }         
665     }
666
667     return res;
668 }
669
670 typedef struct liblist
671 {
672     int flags;
673     int sooffset;
674     int liboffset;
675     char *soname;
676     char *libname;
677     struct liblist *next;
678 } liblist_t;
679
680 static header_t magic = { LDSO_CACHE_MAGIC, LDSO_CACHE_VER, 0 };
681 static liblist_t *lib_head = NULL;
682
683 static int liblistcomp(liblist_t *x, liblist_t *y)
684 {
685     int res;
686
687     if ((res = libcmp(x->soname, y->soname)) == 0)
688     {
689         res = libcmp(strrchr(x->libname, '/') + 1,
690                 strrchr(y->libname, '/') + 1);
691     }
692
693     return res;
694 }
695
696 void cache_dolib(const char *dir, const char *so, int libtype)
697 {
698     char fullpath[PATH_MAX];
699     liblist_t *new_lib, *cur_lib;
700
701     magic.nlibs++;
702     sprintf(fullpath, "%s/%s", dir, so);
703     new_lib = xmalloc(sizeof (liblist_t));
704     new_lib->flags = libtype;
705     new_lib->soname = xstrdup(so);
706     new_lib->libname = xstrdup(fullpath);
707
708     if (lib_head == NULL || liblistcomp(new_lib, lib_head) > 0)
709     {
710         new_lib->next = lib_head;
711         lib_head = new_lib;
712     }
713     else
714     {
715         for (cur_lib = lib_head; cur_lib->next != NULL &&
716                 liblistcomp(new_lib, cur_lib->next) <= 0;
717                 cur_lib = cur_lib->next)
718             /* nothing */;
719         new_lib->next = cur_lib->next;
720         cur_lib->next = new_lib;
721     }
722 }
723
724 void cache_write(void)
725 {
726     int cachefd;
727     int stroffset = 0;
728     char realcachefile[BUFFER_SIZE];
729     char tempfile[BUFFER_SIZE];
730     header_t swap_magic;
731     header_t *magic_ptr;
732     libentry_t swap_lib;
733     libentry_t *lib_ptr;
734     liblist_t *cur_lib;
735
736     if (!magic.nlibs)
737         return;
738
739     if (!chroot_realpath(chroot_dir, cachefile, realcachefile))
740         err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)",
741             cachefile, chroot_dir, strerror(errno));
742
743     sprintf(tempfile, "%s~", realcachefile);
744
745     if (unlink(tempfile) && errno != ENOENT)
746         err(EXIT_FATAL,"can't unlink %s~ (%s)", cachefile, strerror(errno));
747
748     if ((cachefd = creat(tempfile, 0644)) < 0)
749         err(EXIT_FATAL,"can't create %s~ (%s)", cachefile, strerror(errno));
750
751     if (byteswap) {
752         swap_magic = magic;
753         swap_magic.nlibs = bswap_32(swap_magic.nlibs);
754         magic_ptr = &swap_magic;
755     } else {
756         magic_ptr = &magic;
757     }
758     if (write(cachefd, magic_ptr, sizeof (header_t)) != sizeof (header_t))
759         err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
760
761     for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
762     {
763         cur_lib->sooffset = stroffset;
764         stroffset += strlen(cur_lib->soname) + 1;
765         cur_lib->liboffset = stroffset;
766         stroffset += strlen(cur_lib->libname) + 1;
767         if (byteswap) {
768             swap_lib.flags = bswap_32(cur_lib->flags);
769             swap_lib.sooffset = bswap_32(cur_lib->sooffset);
770             swap_lib.liboffset = bswap_32(cur_lib->liboffset);
771             lib_ptr = &swap_lib;
772         } else {
773             lib_ptr = (libentry_t *)cur_lib;
774         }
775         if (write(cachefd, lib_ptr, sizeof (libentry_t)) !=
776             sizeof (libentry_t))
777         err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
778     }
779
780     for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
781     {
782         if ((size_t)write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1)
783                 != strlen(cur_lib->soname) + 1)
784             err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
785         if ((size_t)write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1)
786                 != strlen(cur_lib->libname) + 1)
787             err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
788     }
789
790     if (close(cachefd))
791         err(EXIT_FATAL,"can't close %s~ (%s)", cachefile, strerror(errno));
792
793     if (chmod(tempfile, 0644))
794         err(EXIT_FATAL,"can't chmod %s~ (%s)", cachefile, strerror(errno));
795
796     if (rename(tempfile, realcachefile))
797         err(EXIT_FATAL,"can't rename %s~ (%s)", cachefile, strerror(errno));
798 }
799
800 void cache_print(void)
801 {
802     caddr_t c;
803     struct stat st;
804     int fd = 0;
805     char *strs;
806     header_t *header;
807     libentry_t *libent;
808     char realcachefile[BUFFER_SIZE];
809
810     if (!chroot_realpath(chroot_dir, cachefile, realcachefile))
811         err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)",
812             cachefile, chroot_dir, strerror(errno));
813
814     if (stat(realcachefile, &st) || (fd = open(realcachefile, O_RDONLY))<0)
815         err(EXIT_FATAL,"can't read %s (%s)", cachefile, strerror(errno));
816     if ((c = mmap(0,st.st_size, PROT_READ, LDSO_CACHE_MMAP_FLAGS, fd, 0)) == (caddr_t)-1)
817         err(EXIT_FATAL,"can't map %s (%s)", cachefile, strerror(errno));
818     close(fd);
819
820     if (memcmp(((header_t *)c)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
821         err(EXIT_FATAL,"%s cache corrupt", cachefile);
822
823     if (memcmp(((header_t *)c)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
824         err(EXIT_FATAL,"wrong cache version - expected %s", LDSO_CACHE_VER);
825
826     header = (header_t *)c;
827     libent = (libentry_t *)(c + sizeof (header_t));
828     strs = (char *)&libent[header->nlibs];
829
830     printf("%d libs found in cache `%s' (version %s)\n",
831             header->nlibs, cachefile, LDSO_CACHE_VER);
832
833     for (fd = 0; fd < header->nlibs; fd++)
834     {
835         printf("\t%s ", strs + libent[fd].sooffset);
836         switch (libent[fd].flags & ~LIB_ELF64) 
837         {
838             case LIB_DLL:
839                 printf("(libc4)");
840                 break;
841             case LIB_ELF:
842                 printf("(ELF%s)", libent[fd].flags & LIB_ELF64 ? "/64" : "");
843                 break;
844             case LIB_ELF_LIBC0:
845                 printf("(libc0%s)",libent[fd].flags & LIB_ELF64 ? "/64" : "");
846                 break;
847             case LIB_ELF_LIBC5:
848             case LIB_ELF_LIBC6:
849                 printf("(libc%d%s)", (libent[fd].flags & ~LIB_ELF64) + 3,
850                         libent[fd].flags & LIB_ELF64 ? "/64" : "");
851                 break;
852             default:
853                 printf("(unknown)");
854                 break;
855         }
856         printf(" => %s\n", strs + libent[fd].liboffset);
857     }
858
859     munmap (c,st.st_size);
860 }
861 #endif
862
863 void usage(void)
864 {
865     fprintf(stderr,
866 #ifdef __LDSO_CACHE_SUPPORT__
867             "ldconfig - updates symlinks and cache for shared libraries\n\n"
868             "Usage: ldconfig [-DvqnNX] [-f conf] [-C cache] [-r root] dir ...\n"
869             "       ldconfig -l [-Dv] lib ...\n"
870             "       ldconfig -p\n\nOptions:\n"
871 #else
872             "ldconfig - updates symlinks for shared libraries\n\n"
873             "Usage: ldconfig [-DvqnX] [-r root] dir ...\n"
874             "       ldconfig -l [-Dv] lib ...\n\nOptions:\n"
875 #endif
876             "\t-D:\t\tdebug mode, don't update links\n"
877             "\t-v:\t\tverbose mode, print things as we go\n"
878             "\t-q:\t\tquiet mode, don't print warnings\n"
879             "\t-n:\t\tdon't process standard directories\n"
880             "\t-N:\t\tdon't update the library cache\n"
881             "\t-X:\t\tdon't update the library links\n"
882             "\t-l:\t\tlibrary mode, manually link libraries\n"
883             "\t-p:\t\tprint the current library cache\n"
884 #ifdef __LDSO_CACHE_SUPPORT__
885             "\t-f conf :\tuse conf instead of %s\n"
886             "\t-C cache:\tuse cache instead of %s\n"
887 #endif
888             "\t-r root :\tfirst, do a chroot to the indicated directory\n"
889             "\tdir ... :\tdirectories to process\n"
890 #ifdef __LDSO_CACHE_SUPPORT__
891             "\tlib ... :\tlibraries to link\n\n",
892             LDSO_CONF, LDSO_CACHE
893 #else
894             "\tlib ... :\tlibraries to link\n\n"
895 #endif
896            );
897     exit(EXIT_FATAL);
898 }
899
900 #define DIR_SEP      ":, \t\n"
901 int main(int argc, char **argv)
902 {
903     int i, c;
904     int nodefault = 0;
905     char *cp, *dir, *so;
906     int libtype, islink;
907     int printcache = 0;
908 #ifdef __LDSO_CACHE_SUPPORT__
909     char *extpath;
910 #endif
911
912     prog = argv[0];
913     opterr = 0;
914
915     while ((c = getopt(argc, argv, "DvqnNXlpf:C:r:")) != EOF)
916         switch (c)
917         {
918             case 'D':
919                 debug = 1;              /* debug mode */
920                 nocache = 1;
921                 nolinks = 1;
922                 verbose = 1;
923                 break;
924             case 'v':
925                 verbose = 1;    /* verbose mode */
926                 break;
927             case 'q':
928                 if (verbose <= 0)
929                     verbose = -1;       /* quiet mode */
930                 break;
931             case 'n':
932                 nodefault = 1;  /* no default dirs */
933                 nocache = 1;
934                 break;
935             case 'N':
936                 nocache = 1;    /* don't build cache */
937                 break;
938             case 'X':
939                 nolinks = 1;    /* don't update links */
940                 break;
941             case 'l':
942                 libmode = 1;    /* library mode */
943                 break;
944             case 'p':
945                 printcache = 1; /* print cache */
946                 break;
947             case 'f':
948 #ifdef __LDSO_CACHE_SUPPORT__
949                 conffile = optarg;      /* alternate conf file */
950 #endif
951                 break;
952             case 'C':
953 #ifdef __LDSO_CACHE_SUPPORT__
954                 cachefile = optarg;     /* alternate cache file */
955 #endif
956                 break;
957             case 'r':
958                 chroot_dir = optarg;
959                 break;
960             default:
961                 usage();
962                 break;
963
964                 /* THE REST OF THESE ARE UNDOCUMENTED AND MAY BE REMOVED
965                    IN FUTURE VERSIONS. */
966         }
967
968     if (chroot_dir && *chroot_dir) {
969         if (chroot(chroot_dir) < 0) {
970             if (chdir(chroot_dir) < 0)
971                 err(EXIT_FATAL,"couldn't chroot to %s (%s)", chroot_dir, strerror(errno));
972         }
973         else
974         {
975             if (chdir("/") < 0)
976                 err(EXIT_FATAL,"couldn't chdir to / (%s)", strerror(errno));
977             chroot_dir = NULL;
978         }
979     }
980
981     /* allow me to introduce myself, hi, my name is ... */
982     if (verbose > 0)
983         printf("%s: uClibc version\n", argv[0]);
984
985     if (printcache)
986     {
987         /* print the cache -- don't you trust me? */
988         cache_print();
989         exit(EXIT_OK);
990     }
991     else if (libmode)
992     {
993         /* so you want to do things manually, eh? */
994
995         /* ok, if you're so smart, which libraries do we link? */
996         for (i = optind; i < argc; i++)
997         {
998             /* split into directory and file parts */
999             if (!(cp = strrchr(argv[i], '/')))
1000             {
1001                 dir = ".";      /* no dir, only a filename */
1002                 cp = argv[i];
1003             }
1004             else
1005             {
1006                 if (cp == argv[i])
1007                     dir = "/";  /* file in root directory */
1008                 else
1009                     dir = argv[i];
1010                 *cp++ = '\0';   /* neither of the above */
1011             }
1012
1013             /* we'd better do a little bit of checking */
1014             if ((so = is_shlib(dir, cp, &libtype, &islink, LIB_ANY)) == NULL)
1015                 err(EXIT_FATAL,"%s%s%s is not a shared library", dir,
1016                         (*dir && strcmp(dir, "/")) ? "/" : "", cp);
1017
1018             /* so far, so good, maybe he knows what he's doing */
1019             link_shlib(dir, cp, so);
1020         }
1021     }
1022     else
1023     {
1024         /* the lazy bum want's us to do all the work for him */
1025
1026         /* don't cache dirs on the command line */
1027         int nocache_save = nocache;
1028         nocache = 1;
1029
1030         /* OK, which directories should we do? */
1031         for (i = optind; i < argc; i++)
1032             scan_dir(argv[i]);
1033
1034         /* restore the desired caching state */
1035         nocache = nocache_save;
1036
1037         /* look ma, no defaults */
1038         if (!nodefault)
1039         {
1040             scan_dir(UCLIBC_RUNTIME_PREFIX "lib");
1041             scan_dir(UCLIBC_RUNTIME_PREFIX "usr/lib");
1042 #ifndef __LDSO_CACHE_SUPPORT__
1043             scan_dir(UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib");
1044 #else
1045             /* I guess the defaults aren't good enough */
1046             if ((extpath = get_extpath()))
1047             {
1048                 for (cp = strtok(extpath, DIR_SEP); cp; cp = strtok(NULL, DIR_SEP)) {
1049                         /* strip trailing slashes */
1050                         int len = strlen(cp);
1051                         if (len) 
1052                                 while (cp[--len] == '/' && len)
1053                                         cp[len] = 0;
1054                         /* we do the redundancy check only if cache usage is enabled */
1055                         if (strcmp(UCLIBC_RUNTIME_PREFIX "lib", cp) == 0 ||
1056                             strcmp(UCLIBC_RUNTIME_PREFIX "usr/lib", cp) == 0) {
1057                                 if (verbose >= 0)
1058                                         warnx("You should remove `%s' from `%s'", cp, LDSO_CONF);
1059                                 continue;
1060                         }
1061                     scan_dir(cp);
1062                 }
1063                 free(extpath);
1064             }
1065 #endif
1066         }
1067
1068         if (!nocache)
1069             cache_write();
1070     }
1071
1072     exit(EXIT_OK);
1073 }
1074