Maintain runtime of each benchmark at ~10 seconds
[glibc.git] / elf / cache.c
blob699550bb602f69520ebae20d50486de95a168c15
1 /* Copyright (C) 1999-2013 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
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.
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.
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/>. */
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>
33 #include <ldconfig.h>
34 #include <dl-cache.h>
36 struct cache_entry
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. */
47 /* List of all cache entries. */
48 static struct cache_entry *entries;
50 static const char *flag_descr[] =
51 { "libc4", "ELF", "libc5", "libc6"};
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)
58 printf ("\t%s (", lib);
59 switch (flag & FLAG_TYPE_MASK)
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;
71 switch (flag & FLAG_REQUIRED_MASK)
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 break;
94 case FLAG_X8664_LIBX32:
95 fputs (",x32", stdout);
96 break;
97 case FLAG_ARM_LIBHF:
98 fputs (",hard-float", stdout);
99 break;
100 case FLAG_AARCH64_LIB64:
101 fputs (",AArch64", stdout);
102 break;
103 /* Uses the ARM soft-float ABI. */
104 case FLAG_ARM_LIBSF:
105 fputs (",soft-float", stdout);
106 break;
107 case 0:
108 break;
109 default:
110 printf (",%d", flag & FLAG_REQUIRED_MASK);
111 break;
113 if (hwcap != 0)
114 printf (", hwcap: %#.16" PRIx64, hwcap);
115 if (osversion != 0)
117 static const char *const abi_tag_os[] =
119 [0] = "Linux",
120 [1] = "Hurd",
121 [2] = "Solaris",
122 [3] = "FreeBSD",
123 [4] = "kNetBSD",
124 [5] = "Syllable",
125 [6] = N_("Unknown OS")
127 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
128 unsigned int os = osversion >> 24;
130 printf (_(", OS ABI: %s %d.%d.%d"),
131 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
132 (osversion >> 16) & 0xff,
133 (osversion >> 8) & 0xff,
134 osversion & 0xff);
136 printf (") => %s\n", key);
140 /* Print the whole cache file, if a file contains the new cache format
141 hidden in the old one, print the contents of the new format. */
142 void
143 print_cache (const char *cache_name)
145 int fd = open (cache_name, O_RDONLY);
146 if (fd < 0)
147 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
149 struct stat64 st;
150 if (fstat64 (fd, &st) < 0
151 /* No need to map the file if it is empty. */
152 || st.st_size == 0)
154 close (fd);
155 return;
158 struct cache_file *cache
159 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
160 if (cache == MAP_FAILED)
161 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
163 size_t cache_size = st.st_size;
164 if (cache_size < sizeof (struct cache_file))
165 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
167 struct cache_file_new *cache_new = NULL;
168 const char *cache_data;
169 int format = 0;
171 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
173 /* This can only be the new format without the old one. */
174 cache_new = (struct cache_file_new *) cache;
176 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
177 || memcmp (cache_new->version, CACHE_VERSION,
178 sizeof CACHE_VERSION - 1))
179 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
180 format = 1;
181 /* This is where the strings start. */
182 cache_data = (const char *) cache_new;
184 else
186 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
187 + (cache->nlibs
188 * sizeof (struct file_entry)));
189 /* This is where the strings start. */
190 cache_data = (const char *) &cache->libs[cache->nlibs];
192 /* Check for a new cache embedded in the old format. */
193 if (cache_size >
194 (offset + sizeof (struct cache_file_new)))
197 cache_new = (struct cache_file_new *) ((void *)cache + offset);
199 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
200 sizeof CACHEMAGIC_NEW - 1) == 0
201 && memcmp (cache_new->version, CACHE_VERSION,
202 sizeof CACHE_VERSION - 1) == 0)
204 cache_data = (const char *) cache_new;
205 format = 1;
210 if (format == 0)
212 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
214 /* Print everything. */
215 for (unsigned int i = 0; i < cache->nlibs; i++)
216 print_entry (cache_data + cache->libs[i].key,
217 cache->libs[i].flags, 0, 0,
218 cache_data + cache->libs[i].value);
220 else if (format == 1)
222 printf (_("%d libs found in cache `%s'\n"),
223 cache_new->nlibs, cache_name);
225 /* Print everything. */
226 for (unsigned int i = 0; i < cache_new->nlibs; i++)
227 print_entry (cache_data + cache_new->libs[i].key,
228 cache_new->libs[i].flags,
229 cache_new->libs[i].osversion,
230 cache_new->libs[i].hwcap,
231 cache_data + cache_new->libs[i].value);
233 /* Cleanup. */
234 munmap (cache, cache_size);
235 close (fd);
238 /* Initialize cache data structures. */
239 void
240 init_cache (void)
242 entries = NULL;
245 static int
246 compare (const struct cache_entry *e1, const struct cache_entry *e2)
248 /* We need to swap entries here to get the correct sort order. */
249 int res = _dl_cache_libcmp (e2->lib, e1->lib);
250 if (res == 0)
252 if (e1->flags < e2->flags)
253 return 1;
254 else if (e1->flags > e2->flags)
255 return -1;
256 /* Sort by most specific hwcap. */
257 else if (e2->bits_hwcap > e1->bits_hwcap)
258 return 1;
259 else if (e2->bits_hwcap < e1->bits_hwcap)
260 return -1;
261 else if (e2->hwcap > e1->hwcap)
262 return 1;
263 else if (e2->hwcap < e1->hwcap)
264 return -1;
265 if (e2->osversion > e1->osversion)
266 return 1;
267 if (e2->osversion < e1->osversion)
268 return -1;
270 return res;
273 /* Save the contents of the cache. */
274 void
275 save_cache (const char *cache_name)
277 /* The cache entries are sorted already, save them in this order. */
279 /* Count the length of all strings. */
280 /* The old format doesn't contain hwcap entries and doesn't contain
281 libraries in subdirectories with hwcaps entries. Count therefore
282 also all entries with hwcap == 0. */
283 size_t total_strlen = 0;
284 struct cache_entry *entry;
285 /* Number of cache entries. */
286 int cache_entry_count = 0;
287 /* Number of normal cache entries. */
288 int cache_entry_old_count = 0;
290 for (entry = entries; entry != NULL; entry = entry->next)
292 /* Account the final NULs. */
293 total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
294 ++cache_entry_count;
295 if (entry->hwcap == 0)
296 ++cache_entry_old_count;
299 /* Create the on disk cache structure. */
300 struct cache_file *file_entries = NULL;
301 size_t file_entries_size = 0;
303 if (opt_format != 2)
305 /* struct cache_file_new is 64-bit aligned on some arches while
306 only 32-bit aligned on other arches. Duplicate last old
307 cache entry so that new cache in ld.so.cache can be used by
308 both. */
309 if (opt_format != 0)
310 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
312 /* And the list of all entries in the old format. */
313 file_entries_size = sizeof (struct cache_file)
314 + cache_entry_old_count * sizeof (struct file_entry);
315 file_entries = xmalloc (file_entries_size);
317 /* Fill in the header. */
318 memset (file_entries, '\0', sizeof (struct cache_file));
319 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
321 file_entries->nlibs = cache_entry_old_count;
324 struct cache_file_new *file_entries_new = NULL;
325 size_t file_entries_new_size = 0;
327 if (opt_format != 0)
329 /* And the list of all entries in the new format. */
330 file_entries_new_size = sizeof (struct cache_file_new)
331 + cache_entry_count * sizeof (struct file_entry_new);
332 file_entries_new = xmalloc (file_entries_new_size);
334 /* Fill in the header. */
335 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
336 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
337 sizeof CACHEMAGIC_NEW - 1);
338 memcpy (file_entries_new->version, CACHE_VERSION,
339 sizeof CACHE_VERSION - 1);
341 file_entries_new->nlibs = cache_entry_count;
342 file_entries_new->len_strings = total_strlen;
345 /* Pad for alignment of cache_file_new. */
346 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
348 /* If we have both formats, we hide the new format in the strings
349 table, we have to adjust all string indices for this so that
350 old libc5/glibc 2 dynamic linkers just ignore them. */
351 unsigned int str_offset;
352 if (opt_format != 0)
353 str_offset = file_entries_new_size;
354 else
355 str_offset = 0;
357 /* An array for all strings. */
358 char *strings = xmalloc (total_strlen);
359 char *str = strings;
360 int idx_old;
361 int idx_new;
363 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
364 entry = entry->next, ++idx_new)
366 /* First the library. */
367 if (opt_format != 2 && entry->hwcap == 0)
369 file_entries->libs[idx_old].flags = entry->flags;
370 /* XXX: Actually we can optimize here and remove duplicates. */
371 file_entries->libs[idx_old].key = str_offset + pad;
373 if (opt_format != 0)
375 /* We could subtract file_entries_new_size from str_offset -
376 not doing so makes the code easier, the string table
377 always begins at the beginning of the new cache
378 struct. */
379 file_entries_new->libs[idx_new].flags = entry->flags;
380 file_entries_new->libs[idx_new].osversion = entry->osversion;
381 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
382 file_entries_new->libs[idx_new].key = str_offset;
385 size_t len = strlen (entry->lib) + 1;
386 str = mempcpy (str, entry->lib, len);
387 str_offset += len;
388 /* Then the path. */
389 if (opt_format != 2 && entry->hwcap == 0)
390 file_entries->libs[idx_old].value = str_offset + pad;
391 if (opt_format != 0)
392 file_entries_new->libs[idx_new].value = str_offset;
393 len = strlen (entry->path) + 1;
394 str = mempcpy (str, entry->path, len);
395 str_offset += len;
396 /* Ignore entries with hwcap for old format. */
397 if (entry->hwcap == 0)
398 ++idx_old;
401 /* Duplicate last old cache entry if needed. */
402 if (opt_format != 2
403 && idx_old < cache_entry_old_count)
404 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
406 /* Write out the cache. */
408 /* Write cache first to a temporary file and rename it later. */
409 char *temp_name = xmalloc (strlen (cache_name) + 2);
410 sprintf (temp_name, "%s~", cache_name);
412 /* Create file. */
413 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
414 S_IRUSR|S_IWUSR);
415 if (fd < 0)
416 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
417 temp_name);
419 /* Write contents. */
420 if (opt_format != 2)
422 if (write (fd, file_entries, file_entries_size)
423 != (ssize_t) file_entries_size)
424 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
426 if (opt_format != 0)
428 /* Align cache. */
429 if (opt_format != 2)
431 char zero[pad];
432 memset (zero, '\0', pad);
433 if (write (fd, zero, pad) != (ssize_t) pad)
434 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
436 if (write (fd, file_entries_new, file_entries_new_size)
437 != (ssize_t) file_entries_new_size)
438 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
441 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
442 || close (fd))
443 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
445 /* Make sure user can always read cache file */
446 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
447 error (EXIT_FAILURE, errno,
448 _("Changing access rights of %s to %#o failed"), temp_name,
449 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
451 /* Move temporary to its final location. */
452 if (rename (temp_name, cache_name))
453 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
454 cache_name);
456 /* Free all allocated memory. */
457 free (file_entries_new);
458 free (file_entries);
459 free (strings);
461 while (entries)
463 entry = entries;
464 entries = entries->next;
465 free (entry);
470 /* Add one library to the cache. */
471 void
472 add_to_cache (const char *path, const char *lib, int flags,
473 unsigned int osversion, uint64_t hwcap)
475 size_t liblen = strlen (lib) + 1;
476 size_t len = liblen + strlen (path) + 1;
477 struct cache_entry *new_entry
478 = xmalloc (sizeof (struct cache_entry) + liblen + len);
480 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
481 new_entry->path = new_entry->lib + liblen;
482 snprintf (new_entry->path, len, "%s/%s", path, lib);
483 new_entry->flags = flags;
484 new_entry->osversion = osversion;
485 new_entry->hwcap = hwcap;
486 new_entry->bits_hwcap = 0;
488 /* Count the number of bits set in the masked value. */
489 for (size_t i = 0;
490 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
491 if ((hwcap & (1ULL << i)) != 0)
492 ++new_entry->bits_hwcap;
495 /* Keep the list sorted - search for right place to insert. */
496 struct cache_entry *ptr = entries;
497 struct cache_entry *prev = entries;
498 while (ptr != NULL)
500 if (compare (ptr, new_entry) > 0)
501 break;
502 prev = ptr;
503 ptr = ptr->next;
505 /* Is this the first entry? */
506 if (ptr == entries)
508 new_entry->next = entries;
509 entries = new_entry;
511 else
513 new_entry->next = prev->next;
514 prev->next = new_entry;
519 /* Auxiliary cache. */
521 struct aux_cache_entry_id
523 uint64_t ino;
524 uint64_t ctime;
525 uint64_t size;
526 uint64_t dev;
529 struct aux_cache_entry
531 struct aux_cache_entry_id id;
532 int flags;
533 unsigned int osversion;
534 int used;
535 char *soname;
536 struct aux_cache_entry *next;
539 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
541 struct aux_cache_file_entry
543 struct aux_cache_entry_id id; /* Unique id of entry. */
544 int32_t flags; /* This is 1 for an ELF library. */
545 uint32_t soname; /* String table indice. */
546 uint32_t osversion; /* Required OS version. */
547 int32_t pad;
550 /* ldconfig maintains an auxiliary cache file that allows
551 only reading those libraries that have changed since the last iteration.
552 For this for each library some information is cached in the auxiliary
553 cache. */
554 struct aux_cache_file
556 char magic[sizeof AUX_CACHEMAGIC - 1];
557 uint32_t nlibs; /* Number of entries. */
558 uint32_t len_strings; /* Size of string table. */
559 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
560 /* After this the string table of size len_strings is found. */
563 static const unsigned int primes[] =
565 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
566 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
567 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
570 static size_t aux_hash_size;
571 static struct aux_cache_entry **aux_hash;
573 /* Simplistic hash function for aux_cache_entry_id. */
574 static unsigned int
575 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
577 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
578 return ret ^ (ret >> 32);
581 static size_t nextprime (size_t x)
583 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
584 if (primes[i] >= x)
585 return primes[i];
586 return x;
589 void
590 init_aux_cache (void)
592 aux_hash_size = primes[3];
593 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
597 search_aux_cache (struct stat64 *stat_buf, int *flags,
598 unsigned int *osversion, char **soname)
600 struct aux_cache_entry_id id;
601 id.ino = (uint64_t) stat_buf->st_ino;
602 id.ctime = (uint64_t) stat_buf->st_ctime;
603 id.size = (uint64_t) stat_buf->st_size;
604 id.dev = (uint64_t) stat_buf->st_dev;
606 unsigned int hash = aux_cache_entry_id_hash (&id);
607 struct aux_cache_entry *entry;
608 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
609 if (id.ino == entry->id.ino
610 && id.ctime == entry->id.ctime
611 && id.size == entry->id.size
612 && id.dev == entry->id.dev)
614 *flags = entry->flags;
615 *osversion = entry->osversion;
616 if (entry->soname != NULL)
617 *soname = xstrdup (entry->soname);
618 else
619 *soname = NULL;
620 entry->used = 1;
621 return 1;
624 return 0;
627 static void
628 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
629 unsigned int osversion, const char *soname, int used)
631 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
632 struct aux_cache_entry *entry;
633 for (entry = aux_hash[hash]; entry; entry = entry->next)
634 if (id->ino == entry->id.ino
635 && id->ctime == entry->id.ctime
636 && id->size == entry->id.size
637 && id->dev == entry->id.dev)
638 abort ();
640 size_t len = soname ? strlen (soname) + 1 : 0;
641 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
642 entry->id = *id;
643 entry->flags = flags;
644 entry->osversion = osversion;
645 entry->used = used;
646 if (soname != NULL)
647 entry->soname = memcpy ((char *) (entry + 1), soname, len);
648 else
649 entry->soname = NULL;
650 entry->next = aux_hash[hash];
651 aux_hash[hash] = entry;
654 void
655 add_to_aux_cache (struct stat64 *stat_buf, int flags,
656 unsigned int osversion, const char *soname)
658 struct aux_cache_entry_id id;
659 id.ino = (uint64_t) stat_buf->st_ino;
660 id.ctime = (uint64_t) stat_buf->st_ctime;
661 id.size = (uint64_t) stat_buf->st_size;
662 id.dev = (uint64_t) stat_buf->st_dev;
663 insert_to_aux_cache (&id, flags, osversion, soname, 1);
666 /* Load auxiliary cache to search for unchanged entries. */
667 void
668 load_aux_cache (const char *aux_cache_name)
670 int fd = open (aux_cache_name, O_RDONLY);
671 if (fd < 0)
673 init_aux_cache ();
674 return;
677 struct stat64 st;
678 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
680 close (fd);
681 init_aux_cache ();
682 return;
685 size_t aux_cache_size = st.st_size;
686 struct aux_cache_file *aux_cache
687 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
688 if (aux_cache == MAP_FAILED
689 || aux_cache_size < sizeof (struct aux_cache_file)
690 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
691 || aux_cache->nlibs >= aux_cache_size)
693 close (fd);
694 init_aux_cache ();
695 return;
698 aux_hash_size = nextprime (aux_cache->nlibs);
699 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
701 const char *aux_cache_data
702 = (const char *) &aux_cache->libs[aux_cache->nlibs];
703 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
704 insert_to_aux_cache (&aux_cache->libs[i].id,
705 aux_cache->libs[i].flags,
706 aux_cache->libs[i].osversion,
707 aux_cache->libs[i].soname == 0
708 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
711 munmap (aux_cache, aux_cache_size);
712 close (fd);
715 /* Save the contents of the auxiliary cache. */
716 void
717 save_aux_cache (const char *aux_cache_name)
719 /* Count the length of all sonames. We start with empty string. */
720 size_t total_strlen = 1;
721 /* Number of cache entries. */
722 int cache_entry_count = 0;
724 for (size_t i = 0; i < aux_hash_size; ++i)
725 for (struct aux_cache_entry *entry = aux_hash[i];
726 entry != NULL; entry = entry->next)
727 if (entry->used)
729 ++cache_entry_count;
730 if (entry->soname != NULL)
731 total_strlen += strlen (entry->soname) + 1;
734 /* Auxiliary cache. */
735 size_t file_entries_size
736 = sizeof (struct aux_cache_file)
737 + cache_entry_count * sizeof (struct aux_cache_file_entry);
738 struct aux_cache_file *file_entries
739 = xmalloc (file_entries_size + total_strlen);
741 /* Fill in the header of the auxiliary cache. */
742 memset (file_entries, '\0', sizeof (struct aux_cache_file));
743 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
745 file_entries->nlibs = cache_entry_count;
746 file_entries->len_strings = total_strlen;
748 /* Initial String offset for auxiliary cache is always after the
749 special empty string. */
750 unsigned int str_offset = 1;
752 /* An array for all strings. */
753 char *str = (char *) file_entries + file_entries_size;
754 *str++ = '\0';
756 size_t idx = 0;
757 for (size_t i = 0; i < aux_hash_size; ++i)
758 for (struct aux_cache_entry *entry = aux_hash[i];
759 entry != NULL; entry = entry->next)
760 if (entry->used)
762 file_entries->libs[idx].id = entry->id;
763 file_entries->libs[idx].flags = entry->flags;
764 if (entry->soname == NULL)
765 file_entries->libs[idx].soname = 0;
766 else
768 file_entries->libs[idx].soname = str_offset;
770 size_t len = strlen (entry->soname) + 1;
771 str = mempcpy (str, entry->soname, len);
772 str_offset += len;
774 file_entries->libs[idx].osversion = entry->osversion;
775 file_entries->libs[idx++].pad = 0;
778 /* Write out auxiliary cache file. */
779 /* Write auxiliary cache first to a temporary file and rename it later. */
781 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
782 sprintf (temp_name, "%s~", aux_cache_name);
784 /* Check that directory exists and create if needed. */
785 char *dir = strdupa (aux_cache_name);
786 dir = dirname (dir);
788 struct stat64 st;
789 if (stat64 (dir, &st) < 0)
791 if (mkdir (dir, 0700) < 0)
792 goto out_fail;
795 /* Create file. */
796 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
797 S_IRUSR|S_IWUSR);
798 if (fd < 0)
799 goto out_fail;
801 if (write (fd, file_entries, file_entries_size + total_strlen)
802 != (ssize_t) (file_entries_size + total_strlen)
803 || close (fd))
805 unlink (temp_name);
806 goto out_fail;
809 /* Move temporary to its final location. */
810 if (rename (temp_name, aux_cache_name))
811 unlink (temp_name);
813 out_fail:
814 /* Free allocated memory. */
815 free (temp_name);
816 free (file_entries);