OSDN Git Service

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