OSDN Git Service

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