OSDN Git Service

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