OSDN Git Service

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