OSDN Git Service

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