chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / elf / cache.c
1 /* Copyright (C) 1999-2003,2005,2006,2007 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Andreas Jaeger <aj@suse.de>, 1999.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 #include <errno.h>
20 #include <error.h>
21 #include <dirent.h>
22 #include <inttypes.h>
23 #include <libgen.h>
24 #include <libintl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/fcntl.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33
34 #include <ldconfig.h>
35 #include <dl-cache.h>
36
37 struct cache_entry
38 {
39   char *lib;                    /* Library name.  */
40   char *path;                   /* Path to find library.  */
41   int flags;                    /* Flags to indicate kind of library.  */
42   unsigned int osversion;       /* Required OS version.  */
43   uint64_t hwcap;               /* Important hardware capabilities.  */
44   int bits_hwcap;               /* Number of bits set in hwcap.  */
45   struct cache_entry *next;     /* Next entry in list.  */
46 };
47
48 /* List of all cache entries.  */
49 static struct cache_entry *entries;
50
51 static const char *flag_descr[] =
52 { "libc4", "ELF", "libc5", "libc6"};
53
54 /* Print a single entry.  */
55 static void
56 print_entry (const char *lib, int flag, unsigned int osversion,
57              uint64_t hwcap, const char *key)
58 {
59   printf ("\t%s (", lib);
60   switch (flag & FLAG_TYPE_MASK)
61     {
62     case FLAG_LIBC4:
63     case FLAG_ELF:
64     case FLAG_ELF_LIBC5:
65     case FLAG_ELF_LIBC6:
66       fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
67       break;
68     default:
69       fputs (_("unknown"), stdout);
70       break;
71     }
72   switch (flag & FLAG_REQUIRED_MASK)
73     {
74     case FLAG_SPARC_LIB64:
75       fputs (",64bit", stdout);
76       break;
77     case FLAG_IA64_LIB64:
78       fputs (",IA-64", stdout);
79       break;
80     case FLAG_X8664_LIB64:
81       fputs (",x86-64", stdout);
82       break;
83     case FLAG_S390_LIB64:
84       fputs (",64bit", stdout);
85       break;
86     case FLAG_POWERPC_LIB64:
87       fputs (",64bit", stdout);
88       break;
89     case FLAG_MIPS64_LIBN32:
90       fputs (",N32", stdout);
91       break;
92     case FLAG_MIPS64_LIBN64:
93       fputs (",64bit", stdout);
94     case 0:
95       break;
96     default:
97       printf (",%d", flag & FLAG_REQUIRED_MASK);
98       break;
99     }
100   if (hwcap != 0)
101     printf (", hwcap: %#.16" PRIx64, hwcap);
102   if (osversion != 0)
103     {
104       static const char *const abi_tag_os[] =
105       {
106         [0] = "Linux",
107         [1] = "Hurd",
108         [2] = "Solaris",
109         [3] = "FreeBSD",
110         [4] = "kNetBSD",
111         [5] = "Syllable",
112         [6] = N_("Unknown OS")
113       };
114 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
115       unsigned int os = osversion >> 24;
116
117       printf (_(", OS ABI: %s %d.%d.%d"),
118               _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
119               (osversion >> 16) & 0xff,
120               (osversion >> 8) & 0xff,
121               osversion & 0xff);
122     }
123   printf (") => %s\n", key);
124 }
125
126
127 /* Print the whole cache file, if a file contains the new cache format
128    hidden in the old one, print the contents of the new format.  */
129 void
130 print_cache (const char *cache_name)
131 {
132   int fd = open (cache_name, O_RDONLY);
133   if (fd < 0)
134     error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
135
136   struct stat64 st;
137   if (fstat64 (fd, &st) < 0
138       /* No need to map the file if it is empty.  */
139       || st.st_size == 0)
140     {
141       close (fd);
142       return;
143     }
144
145   struct cache_file *cache
146     = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
147   if (cache == MAP_FAILED)
148     error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
149
150   size_t cache_size = st.st_size;
151   if (cache_size < sizeof (struct cache_file))
152     error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
153
154   struct cache_file_new *cache_new = NULL;
155   const char *cache_data;
156   int format = 0;
157
158   if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
159     {
160       /* This can only be the new format without the old one.  */
161       cache_new = (struct cache_file_new *) cache;
162
163       if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
164           || memcmp (cache_new->version, CACHE_VERSION,
165                       sizeof CACHE_VERSION - 1))
166         error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
167       format = 1;
168       /* This is where the strings start.  */
169       cache_data = (const char *) cache_new;
170     }
171   else
172     {
173       size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
174                                    + (cache->nlibs
175                                       * sizeof (struct file_entry)));
176       /* This is where the strings start.  */
177       cache_data = (const char *) &cache->libs[cache->nlibs];
178
179       /* Check for a new cache embedded in the old format.  */
180       if (cache_size >
181           (offset + sizeof (struct cache_file_new)))
182         {
183
184           cache_new = (struct cache_file_new *) ((void *)cache + offset);
185
186           if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
187                       sizeof CACHEMAGIC_NEW - 1) == 0
188               && memcmp (cache_new->version, CACHE_VERSION,
189                          sizeof CACHE_VERSION - 1) == 0)
190             {
191               cache_data = (const char *) cache_new;
192               format = 1;
193             }
194         }
195     }
196
197   if (format == 0)
198     {
199       printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
200
201       /* Print everything.  */
202       for (unsigned int i = 0; i < cache->nlibs; i++)
203         print_entry (cache_data + cache->libs[i].key,
204                      cache->libs[i].flags, 0, 0,
205                      cache_data + cache->libs[i].value);
206     }
207   else if (format == 1)
208     {
209       printf (_("%d libs found in cache `%s'\n"),
210               cache_new->nlibs, cache_name);
211
212       /* Print everything.  */
213       for (unsigned int i = 0; i < cache_new->nlibs; i++)
214         print_entry (cache_data + cache_new->libs[i].key,
215                      cache_new->libs[i].flags,
216                      cache_new->libs[i].osversion,
217                      cache_new->libs[i].hwcap,
218                      cache_data + cache_new->libs[i].value);
219     }
220   /* Cleanup.  */
221   munmap (cache, cache_size);
222   close (fd);
223 }
224
225 /* Initialize cache data structures.  */
226 void
227 init_cache (void)
228 {
229   entries = NULL;
230 }
231
232 static int
233 compare (const struct cache_entry *e1, const struct cache_entry *e2)
234 {
235   /* We need to swap entries here to get the correct sort order.  */
236   int res = _dl_cache_libcmp (e2->lib, e1->lib);
237   if (res == 0)
238     {
239       if (e1->flags < e2->flags)
240         return 1;
241       else if (e1->flags > e2->flags)
242         return -1;
243       /* Sort by most specific hwcap.  */
244       else if (e2->bits_hwcap > e1->bits_hwcap)
245         return 1;
246       else if (e2->bits_hwcap < e1->bits_hwcap)
247         return -1;
248       else if (e2->hwcap > e1->hwcap)
249         return 1;
250       else if (e2->hwcap < e1->hwcap)
251         return -1;
252       if (e2->osversion > e1->osversion)
253         return 1;
254       if (e2->osversion < e1->osversion)
255         return -1;
256     }
257   return res;
258 }
259
260 /* Save the contents of the cache.  */
261 void
262 save_cache (const char *cache_name)
263 {
264   /* The cache entries are sorted already, save them in this order. */
265
266   /* Count the length of all strings.  */
267   /* The old format doesn't contain hwcap entries and doesn't contain
268      libraries in subdirectories with hwcaps entries.  Count therefore
269      also all entries with hwcap == 0.  */
270   size_t total_strlen = 0;
271   struct cache_entry *entry;
272   /* Number of cache entries.  */
273   int cache_entry_count = 0;
274   /* Number of normal cache entries.  */
275   int cache_entry_old_count = 0;
276
277   for (entry = entries; entry != NULL; entry = entry->next)
278     {
279       /* Account the final NULs.  */
280       total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
281       ++cache_entry_count;
282       if (entry->hwcap == 0)
283         ++cache_entry_old_count;
284     }
285
286   /* Create the on disk cache structure.  */
287   struct cache_file *file_entries = NULL;
288   size_t file_entries_size = 0;
289
290   if (opt_format != 2)
291     {
292       /* struct cache_file_new is 64-bit aligned on some arches while
293          only 32-bit aligned on other arches.  Duplicate last old
294          cache entry so that new cache in ld.so.cache can be used by
295          both.  */
296       if (opt_format != 0)
297         cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
298
299       /* And the list of all entries in the old format.  */
300       file_entries_size = sizeof (struct cache_file)
301         + cache_entry_old_count * sizeof (struct file_entry);
302       file_entries = xmalloc (file_entries_size);
303
304       /* Fill in the header.  */
305       memset (file_entries, '\0', sizeof (struct cache_file));
306       memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
307
308       file_entries->nlibs = cache_entry_old_count;
309     }
310
311   struct cache_file_new *file_entries_new = NULL;
312   size_t file_entries_new_size = 0;
313
314   if (opt_format != 0)
315     {
316       /* And the list of all entries in the new format.  */
317       file_entries_new_size = sizeof (struct cache_file_new)
318         + cache_entry_count * sizeof (struct file_entry_new);
319       file_entries_new = xmalloc (file_entries_new_size);
320
321       /* Fill in the header.  */
322       memset (file_entries_new, '\0', sizeof (struct cache_file_new));
323       memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
324               sizeof CACHEMAGIC_NEW - 1);
325       memcpy (file_entries_new->version, CACHE_VERSION,
326               sizeof CACHE_VERSION - 1);
327
328       file_entries_new->nlibs = cache_entry_count;
329       file_entries_new->len_strings = total_strlen;
330     }
331
332   /* Pad for alignment of cache_file_new.  */
333   size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
334
335   /* If we have both formats, we hide the new format in the strings
336      table, we have to adjust all string indices for this so that
337      old libc5/glibc 2 dynamic linkers just ignore them.  */
338   unsigned int str_offset;
339   if (opt_format != 0)
340     str_offset = file_entries_new_size;
341   else
342     str_offset = 0;
343
344   /* An array for all strings.  */
345   char *strings = xmalloc (total_strlen);
346   char *str = strings;
347   int idx_old;
348   int idx_new;
349
350   for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
351        entry = entry->next, ++idx_new)
352     {
353       /* First the library.  */
354       if (opt_format != 2 && entry->hwcap == 0)
355         {
356           file_entries->libs[idx_old].flags = entry->flags;
357           /* XXX: Actually we can optimize here and remove duplicates.  */
358           file_entries->libs[idx_old].key = str_offset + pad;
359         }
360       if (opt_format != 0)
361         {
362           /* We could subtract file_entries_new_size from str_offset -
363              not doing so makes the code easier, the string table
364              always begins at the beginning of the the new cache
365              struct.  */
366           file_entries_new->libs[idx_new].flags = entry->flags;
367           file_entries_new->libs[idx_new].osversion = entry->osversion;
368           file_entries_new->libs[idx_new].hwcap = entry->hwcap;
369           file_entries_new->libs[idx_new].key = str_offset;
370         }
371
372       size_t len = strlen (entry->lib) + 1;
373       str = mempcpy (str, entry->lib, len);
374       str_offset += len;
375       /* Then the path.  */
376       if (opt_format != 2 && entry->hwcap == 0)
377         file_entries->libs[idx_old].value = str_offset + pad;
378       if (opt_format != 0)
379         file_entries_new->libs[idx_new].value = str_offset;
380       len = strlen (entry->path) + 1;
381       str = mempcpy (str, entry->path, len);
382       str_offset += len;
383       /* Ignore entries with hwcap for old format.  */
384       if (entry->hwcap == 0)
385         ++idx_old;
386     }
387
388   /* Duplicate last old cache entry if needed.  */
389   if (opt_format != 2
390       && idx_old < cache_entry_old_count)
391     file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
392
393   /* Write out the cache.  */
394
395   /* Write cache first to a temporary file and rename it later.  */
396   char *temp_name = xmalloc (strlen (cache_name) + 2);
397   sprintf (temp_name, "%s~", cache_name);
398
399   /* Create file.  */
400   int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
401                  S_IRUSR|S_IWUSR);
402   if (fd < 0)
403     error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
404            temp_name);
405
406   /* Write contents.  */
407   if (opt_format != 2)
408     {
409       if (write (fd, file_entries, file_entries_size)
410           != (ssize_t) file_entries_size)
411         error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
412     }
413   if (opt_format != 0)
414     {
415       /* Align cache.  */
416       if (opt_format != 2)
417         {
418           char zero[pad];
419           memset (zero, '\0', pad);
420           if (write (fd, zero, pad) != (ssize_t) pad)
421             error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
422         }
423       if (write (fd, file_entries_new, file_entries_new_size)
424           != (ssize_t) file_entries_new_size)
425         error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
426     }
427
428   if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
429       || close (fd))
430     error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
431
432   /* Make sure user can always read cache file */
433   if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
434     error (EXIT_FAILURE, errno,
435            _("Changing access rights of %s to %#o failed"), temp_name,
436            S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
437
438   /* Move temporary to its final location.  */
439   if (rename (temp_name, cache_name))
440     error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
441            cache_name);
442
443   /* Free all allocated memory.  */
444   free (file_entries_new);
445   free (file_entries);
446   free (strings);
447
448   while (entries)
449     {
450       entry = entries;
451       entries = entries->next;
452       free (entry);
453     }
454 }
455
456
457 /* Add one library to the cache.  */
458 void
459 add_to_cache (const char *path, const char *lib, int flags,
460               unsigned int osversion, uint64_t hwcap)
461 {
462   size_t liblen = strlen (lib) + 1;
463   size_t len = liblen + strlen (path) + 1;
464   struct cache_entry *new_entry
465     = xmalloc (sizeof (struct cache_entry) + liblen + len);
466
467   new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
468   new_entry->path = new_entry->lib + liblen;
469   snprintf (new_entry->path, len, "%s/%s", path, lib);
470   new_entry->flags = flags;
471   new_entry->osversion = osversion;
472   new_entry->hwcap = hwcap;
473   new_entry->bits_hwcap = 0;
474
475   /* Count the number of bits set in the masked value.  */
476   for (size_t i = 0;
477        (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
478     if ((hwcap & (1ULL << i)) != 0)
479       ++new_entry->bits_hwcap;
480
481
482   /* Keep the list sorted - search for right place to insert.  */
483   struct cache_entry *ptr = entries;
484   struct cache_entry *prev = entries;
485   while (ptr != NULL)
486     {
487       if (compare (ptr, new_entry) > 0)
488         break;
489       prev = ptr;
490       ptr = ptr->next;
491     }
492   /* Is this the first entry?  */
493   if (ptr == entries)
494     {
495       new_entry->next = entries;
496       entries = new_entry;
497     }
498   else
499     {
500       new_entry->next = prev->next;
501       prev->next = new_entry;
502     }
503 }
504
505
506 /* Auxiliary cache.  */
507
508 struct aux_cache_entry_id
509 {
510   uint64_t ino;
511   uint64_t ctime;
512   uint64_t size;
513   uint64_t dev;
514 };
515
516 struct aux_cache_entry
517 {
518   struct aux_cache_entry_id id;
519   int flags;
520   unsigned int osversion;
521   int used;
522   char *soname;
523   struct aux_cache_entry *next;
524 };
525
526 #define AUX_CACHEMAGIC          "glibc-ld.so.auxcache-1.0"
527
528 struct aux_cache_file_entry
529 {
530   struct aux_cache_entry_id id; /* Unique id of entry.  */
531   int32_t flags;                /* This is 1 for an ELF library.  */
532   uint32_t soname;              /* String table indice.  */
533   uint32_t osversion;           /* Required OS version.  */
534   int32_t pad;
535 };
536
537 /* ldconfig maintains an auxiliary cache file that allows
538    only reading those libraries that have changed since the last iteration.
539    For this for each library some information is cached in the auxiliary
540    cache.  */
541 struct aux_cache_file
542 {
543   char magic[sizeof AUX_CACHEMAGIC - 1];
544   uint32_t nlibs;               /* Number of entries.  */
545   uint32_t len_strings;         /* Size of string table. */
546   struct aux_cache_file_entry libs[0]; /* Entries describing libraries.  */
547   /* After this the string table of size len_strings is found.  */
548 };
549
550 static const unsigned int primes[] =
551 {
552   1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
553   524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
554   67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
555 };
556
557 static size_t aux_hash_size;
558 static struct aux_cache_entry **aux_hash;
559
560 /* Simplistic hash function for aux_cache_entry_id.  */
561 static unsigned int
562 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
563 {
564   uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
565   return ret ^ (ret >> 32);
566 }
567
568 static size_t nextprime (size_t x)
569 {
570   for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
571     if (primes[i] >= x)
572       return primes[i];
573   return x;
574 }
575
576 void
577 init_aux_cache (void)
578 {
579   aux_hash_size = primes[3];
580   aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
581 }
582
583 int
584 search_aux_cache (struct stat64 *stat_buf, int *flags,
585                   unsigned int *osversion, char **soname)
586 {
587   struct aux_cache_entry_id id;
588   id.ino = (uint64_t) stat_buf->st_ino;
589   id.ctime = (uint64_t) stat_buf->st_ctime;
590   id.size = (uint64_t) stat_buf->st_size;
591   id.dev = (uint64_t) stat_buf->st_dev;
592
593   unsigned int hash = aux_cache_entry_id_hash (&id);
594   struct aux_cache_entry *entry;
595   for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
596     if (id.ino == entry->id.ino
597         && id.ctime == entry->id.ctime
598         && id.size == entry->id.size
599         && id.dev == entry->id.dev)
600       {
601         *flags = entry->flags;
602         *osversion = entry->osversion;
603         if (entry->soname != NULL)
604           *soname = xstrdup (entry->soname);
605         else
606           *soname = NULL;
607         entry->used = 1;
608         return 1;
609       }
610
611   return 0;
612 }
613
614 static void
615 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
616                      unsigned int osversion, const char *soname, int used)
617 {
618   size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
619   struct aux_cache_entry *entry;
620   for (entry = aux_hash[hash]; entry; entry = entry->next)
621     if (id->ino == entry->id.ino
622         && id->ctime == entry->id.ctime
623         && id->size == entry->id.size
624         && id->dev == entry->id.dev)
625       abort ();
626
627   size_t len = soname ? strlen (soname) + 1 : 0;
628   entry = xmalloc (sizeof (struct aux_cache_entry) + len);
629   entry->id = *id;
630   entry->flags = flags;
631   entry->osversion = osversion;
632   entry->used = used;
633   if (soname != NULL)
634     entry->soname = memcpy ((char *) (entry + 1), soname, len);
635   else
636     entry->soname = NULL;
637   entry->next = aux_hash[hash];
638   aux_hash[hash] = entry;
639 }
640
641 void
642 add_to_aux_cache (struct stat64 *stat_buf, int flags,
643                   unsigned int osversion, const char *soname)
644 {
645   struct aux_cache_entry_id id;
646   id.ino = (uint64_t) stat_buf->st_ino;
647   id.ctime = (uint64_t) stat_buf->st_ctime;
648   id.size = (uint64_t) stat_buf->st_size;
649   id.dev = (uint64_t) stat_buf->st_dev;
650   insert_to_aux_cache (&id, flags, osversion, soname, 1);
651 }
652
653 /* Load auxiliary cache to search for unchanged entries.   */
654 void
655 load_aux_cache (const char *aux_cache_name)
656 {
657   int fd = open (aux_cache_name, O_RDONLY);
658   if (fd < 0)
659     {
660       init_aux_cache ();
661       return;
662     }
663
664   struct stat64 st;
665   if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
666     {
667       close (fd);
668       init_aux_cache ();
669       return;
670     }
671
672   size_t aux_cache_size = st.st_size;
673   struct aux_cache_file *aux_cache
674     = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
675   if (aux_cache == MAP_FAILED
676       || aux_cache_size < sizeof (struct aux_cache_file)
677       || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
678       || aux_cache->nlibs < 0
679       || aux_cache->nlibs >= aux_cache_size)
680     {
681       close (fd);
682       init_aux_cache ();
683       return;
684     }
685
686   aux_hash_size = nextprime (aux_cache->nlibs);
687   aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
688
689   const char *aux_cache_data
690     = (const char *) &aux_cache->libs[aux_cache->nlibs];
691   for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
692     insert_to_aux_cache (&aux_cache->libs[i].id,
693                          aux_cache->libs[i].flags,
694                          aux_cache->libs[i].osversion,
695                          aux_cache->libs[i].soname == 0
696                          ? NULL : aux_cache_data + aux_cache->libs[i].soname,
697                          0);
698
699   munmap (aux_cache, aux_cache_size);
700   close (fd);
701 }
702
703 /* Save the contents of the auxiliary cache.  */
704 void
705 save_aux_cache (const char *aux_cache_name)
706 {
707   /* Count the length of all sonames.  We start with empty string.  */
708   size_t total_strlen = 1;
709   /* Number of cache entries.  */
710   int cache_entry_count = 0;
711
712   for (size_t i = 0; i < aux_hash_size; ++i)
713     for (struct aux_cache_entry *entry = aux_hash[i];
714          entry != NULL; entry = entry->next)
715       if (entry->used)
716         {
717           ++cache_entry_count;
718           if (entry->soname != NULL)
719             total_strlen += strlen (entry->soname) + 1;
720         }
721
722   /* Auxiliary cache.  */
723   size_t file_entries_size
724     = sizeof (struct aux_cache_file)
725       + cache_entry_count * sizeof (struct aux_cache_file_entry);
726   struct aux_cache_file *file_entries
727     = xmalloc (file_entries_size + total_strlen);
728
729   /* Fill in the header of the auxiliary cache.  */
730   memset (file_entries, '\0', sizeof (struct aux_cache_file));
731   memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
732
733   file_entries->nlibs = cache_entry_count;
734   file_entries->len_strings = total_strlen;
735
736   /* Initial String offset for auxiliary cache is always after the
737      special empty string.  */
738   unsigned int str_offset = 1;
739
740   /* An array for all strings.  */
741   char *str = (char *) file_entries + file_entries_size;
742   *str++ = '\0';
743
744   size_t idx = 0;
745   for (size_t i = 0; i < aux_hash_size; ++i)
746     for (struct aux_cache_entry *entry = aux_hash[i];
747          entry != NULL; entry = entry->next)
748       if (entry->used)
749         {
750           file_entries->libs[idx].id = entry->id;
751           file_entries->libs[idx].flags = entry->flags;
752           if (entry->soname == NULL)
753             file_entries->libs[idx].soname = 0;
754           else
755             {
756               file_entries->libs[idx].soname = str_offset;
757
758               size_t len = strlen (entry->soname) + 1;
759               str = mempcpy (str, entry->soname, len);
760               str_offset += len;
761             }
762           file_entries->libs[idx].osversion = entry->osversion;
763           file_entries->libs[idx++].pad = 0;
764         }
765
766   /* Write out auxiliary cache file.  */
767   /* Write auxiliary cache first to a temporary file and rename it later.  */
768
769   char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
770   sprintf (temp_name, "%s~", aux_cache_name);
771
772   /* Check that directory exists and create if needed.  */
773   char *dir = strdupa (aux_cache_name);
774   dir = dirname (dir);
775
776   struct stat64 st;
777   if (stat64 (dir, &st) < 0)
778     {
779       if (mkdir (dir, 0700) < 0)
780         goto out_fail;
781     }
782
783   /* Create file.  */
784   int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
785                  S_IRUSR|S_IWUSR);
786   if (fd < 0)
787     goto out_fail;
788
789   if (write (fd, file_entries, file_entries_size + total_strlen)
790       != (ssize_t) (file_entries_size + total_strlen)
791       || close (fd))
792     {
793       unlink (temp_name);
794       goto out_fail;
795     }
796
797   /* Move temporary to its final location.  */
798   if (rename (temp_name, aux_cache_name))
799     unlink (temp_name);
800
801 out_fail:
802   /* Free allocated memory.  */
803   free (temp_name);
804   free (file_entries);
805 }