OSDN Git Service

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