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