Add a test for BZ #15674
[glibc.git] / elf / cache.c
blob9bf261cd298db8baf8a4c8ca4ff5faea6c19d89d
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 <stdint.h>
29 #include <sys/fcntl.h>
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
34 #include <ldconfig.h>
35 #include <dl-cache.h>
37 struct cache_entry
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. */
48 /* List of all cache entries. */
49 static struct cache_entry *entries;
51 static const char *flag_descr[] =
52 { "libc4", "ELF", "libc5", "libc6"};
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)
59 printf ("\t%s (", lib);
60 switch (flag & FLAG_TYPE_MASK)
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;
72 switch (flag & FLAG_REQUIRED_MASK)
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 break;
95 case FLAG_X8664_LIBX32:
96 fputs (",x32", stdout);
97 break;
98 case FLAG_ARM_LIBHF:
99 fputs (",hard-float", stdout);
100 break;
101 case FLAG_AARCH64_LIB64:
102 fputs (",AArch64", stdout);
103 break;
104 /* Uses the ARM soft-float ABI. */
105 case FLAG_ARM_LIBSF:
106 fputs (",soft-float", stdout);
107 break;
108 case 0:
109 break;
110 default:
111 printf (",%d", flag & FLAG_REQUIRED_MASK);
112 break;
114 if (hwcap != 0)
115 printf (", hwcap: %#.16" PRIx64, hwcap);
116 if (osversion != 0)
118 static const char *const abi_tag_os[] =
120 [0] = "Linux",
121 [1] = "Hurd",
122 [2] = "Solaris",
123 [3] = "FreeBSD",
124 [4] = "kNetBSD",
125 [5] = "Syllable",
126 [6] = N_("Unknown OS")
128 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
129 unsigned int os = osversion >> 24;
131 printf (_(", OS ABI: %s %d.%d.%d"),
132 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
133 (osversion >> 16) & 0xff,
134 (osversion >> 8) & 0xff,
135 osversion & 0xff);
137 printf (") => %s\n", key);
141 /* Print the whole cache file, if a file contains the new cache format
142 hidden in the old one, print the contents of the new format. */
143 void
144 print_cache (const char *cache_name)
146 int fd = open (cache_name, O_RDONLY);
147 if (fd < 0)
148 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
150 struct stat64 st;
151 if (fstat64 (fd, &st) < 0
152 /* No need to map the file if it is empty. */
153 || st.st_size == 0)
155 close (fd);
156 return;
159 struct cache_file *cache
160 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
161 if (cache == MAP_FAILED)
162 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
164 size_t cache_size = st.st_size;
165 if (cache_size < sizeof (struct cache_file))
166 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
168 struct cache_file_new *cache_new = NULL;
169 const char *cache_data;
170 int format = 0;
172 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
174 /* This can only be the new format without the old one. */
175 cache_new = (struct cache_file_new *) cache;
177 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
178 || memcmp (cache_new->version, CACHE_VERSION,
179 sizeof CACHE_VERSION - 1))
180 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
181 format = 1;
182 /* This is where the strings start. */
183 cache_data = (const char *) cache_new;
185 else
187 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
188 + (cache->nlibs
189 * sizeof (struct file_entry)));
190 /* This is where the strings start. */
191 cache_data = (const char *) &cache->libs[cache->nlibs];
193 /* Check for a new cache embedded in the old format. */
194 if (cache_size >
195 (offset + sizeof (struct cache_file_new)))
198 cache_new = (struct cache_file_new *) ((void *)cache + offset);
200 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
201 sizeof CACHEMAGIC_NEW - 1) == 0
202 && memcmp (cache_new->version, CACHE_VERSION,
203 sizeof CACHE_VERSION - 1) == 0)
205 cache_data = (const char *) cache_new;
206 format = 1;
211 if (format == 0)
213 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
215 /* Print everything. */
216 for (unsigned int i = 0; i < cache->nlibs; i++)
217 print_entry (cache_data + cache->libs[i].key,
218 cache->libs[i].flags, 0, 0,
219 cache_data + cache->libs[i].value);
221 else if (format == 1)
223 printf (_("%d libs found in cache `%s'\n"),
224 cache_new->nlibs, cache_name);
226 /* Print everything. */
227 for (unsigned int i = 0; i < cache_new->nlibs; i++)
228 print_entry (cache_data + cache_new->libs[i].key,
229 cache_new->libs[i].flags,
230 cache_new->libs[i].osversion,
231 cache_new->libs[i].hwcap,
232 cache_data + cache_new->libs[i].value);
234 /* Cleanup. */
235 munmap (cache, cache_size);
236 close (fd);
239 /* Initialize cache data structures. */
240 void
241 init_cache (void)
243 entries = NULL;
246 static int
247 compare (const struct cache_entry *e1, const struct cache_entry *e2)
249 /* We need to swap entries here to get the correct sort order. */
250 int res = _dl_cache_libcmp (e2->lib, e1->lib);
251 if (res == 0)
253 if (e1->flags < e2->flags)
254 return 1;
255 else if (e1->flags > e2->flags)
256 return -1;
257 /* Sort by most specific hwcap. */
258 else if (e2->bits_hwcap > e1->bits_hwcap)
259 return 1;
260 else if (e2->bits_hwcap < e1->bits_hwcap)
261 return -1;
262 else if (e2->hwcap > e1->hwcap)
263 return 1;
264 else if (e2->hwcap < e1->hwcap)
265 return -1;
266 if (e2->osversion > e1->osversion)
267 return 1;
268 if (e2->osversion < e1->osversion)
269 return -1;
271 return res;
274 /* Save the contents of the cache. */
275 void
276 save_cache (const char *cache_name)
278 /* The cache entries are sorted already, save them in this order. */
280 /* Count the length of all strings. */
281 /* The old format doesn't contain hwcap entries and doesn't contain
282 libraries in subdirectories with hwcaps entries. Count therefore
283 also all entries with hwcap == 0. */
284 size_t total_strlen = 0;
285 struct cache_entry *entry;
286 /* Number of cache entries. */
287 int cache_entry_count = 0;
288 /* Number of normal cache entries. */
289 int cache_entry_old_count = 0;
291 for (entry = entries; entry != NULL; entry = entry->next)
293 /* Account the final NULs. */
294 total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
295 ++cache_entry_count;
296 if (entry->hwcap == 0)
297 ++cache_entry_old_count;
300 /* Create the on disk cache structure. */
301 struct cache_file *file_entries = NULL;
302 size_t file_entries_size = 0;
304 if (opt_format != 2)
306 /* struct cache_file_new is 64-bit aligned on some arches while
307 only 32-bit aligned on other arches. Duplicate last old
308 cache entry so that new cache in ld.so.cache can be used by
309 both. */
310 if (opt_format != 0)
311 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
313 /* And the list of all entries in the old format. */
314 file_entries_size = sizeof (struct cache_file)
315 + cache_entry_old_count * sizeof (struct file_entry);
316 file_entries = xmalloc (file_entries_size);
318 /* Fill in the header. */
319 memset (file_entries, '\0', sizeof (struct cache_file));
320 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
322 file_entries->nlibs = cache_entry_old_count;
325 struct cache_file_new *file_entries_new = NULL;
326 size_t file_entries_new_size = 0;
328 if (opt_format != 0)
330 /* And the list of all entries in the new format. */
331 file_entries_new_size = sizeof (struct cache_file_new)
332 + cache_entry_count * sizeof (struct file_entry_new);
333 file_entries_new = xmalloc (file_entries_new_size);
335 /* Fill in the header. */
336 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
337 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
338 sizeof CACHEMAGIC_NEW - 1);
339 memcpy (file_entries_new->version, CACHE_VERSION,
340 sizeof CACHE_VERSION - 1);
342 file_entries_new->nlibs = cache_entry_count;
343 file_entries_new->len_strings = total_strlen;
346 /* Pad for alignment of cache_file_new. */
347 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
349 /* If we have both formats, we hide the new format in the strings
350 table, we have to adjust all string indices for this so that
351 old libc5/glibc 2 dynamic linkers just ignore them. */
352 unsigned int str_offset;
353 if (opt_format != 0)
354 str_offset = file_entries_new_size;
355 else
356 str_offset = 0;
358 /* An array for all strings. */
359 char *strings = xmalloc (total_strlen);
360 char *str = strings;
361 int idx_old;
362 int idx_new;
364 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
365 entry = entry->next, ++idx_new)
367 /* First the library. */
368 if (opt_format != 2 && entry->hwcap == 0)
370 file_entries->libs[idx_old].flags = entry->flags;
371 /* XXX: Actually we can optimize here and remove duplicates. */
372 file_entries->libs[idx_old].key = str_offset + pad;
374 if (opt_format != 0)
376 /* We could subtract file_entries_new_size from str_offset -
377 not doing so makes the code easier, the string table
378 always begins at the beginning of the new cache
379 struct. */
380 file_entries_new->libs[idx_new].flags = entry->flags;
381 file_entries_new->libs[idx_new].osversion = entry->osversion;
382 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
383 file_entries_new->libs[idx_new].key = str_offset;
386 size_t len = strlen (entry->lib) + 1;
387 str = mempcpy (str, entry->lib, len);
388 str_offset += len;
389 /* Then the path. */
390 if (opt_format != 2 && entry->hwcap == 0)
391 file_entries->libs[idx_old].value = str_offset + pad;
392 if (opt_format != 0)
393 file_entries_new->libs[idx_new].value = str_offset;
394 len = strlen (entry->path) + 1;
395 str = mempcpy (str, entry->path, len);
396 str_offset += len;
397 /* Ignore entries with hwcap for old format. */
398 if (entry->hwcap == 0)
399 ++idx_old;
402 /* Duplicate last old cache entry if needed. */
403 if (opt_format != 2
404 && idx_old < cache_entry_old_count)
405 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
407 /* Write out the cache. */
409 /* Write cache first to a temporary file and rename it later. */
410 char *temp_name = xmalloc (strlen (cache_name) + 2);
411 sprintf (temp_name, "%s~", cache_name);
413 /* Create file. */
414 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
415 S_IRUSR|S_IWUSR);
416 if (fd < 0)
417 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
418 temp_name);
420 /* Write contents. */
421 if (opt_format != 2)
423 if (write (fd, file_entries, file_entries_size)
424 != (ssize_t) file_entries_size)
425 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
427 if (opt_format != 0)
429 /* Align cache. */
430 if (opt_format != 2)
432 char zero[pad];
433 memset (zero, '\0', pad);
434 if (write (fd, zero, pad) != (ssize_t) pad)
435 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
437 if (write (fd, file_entries_new, file_entries_new_size)
438 != (ssize_t) file_entries_new_size)
439 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
442 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
443 || close (fd))
444 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
446 /* Make sure user can always read cache file */
447 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
448 error (EXIT_FAILURE, errno,
449 _("Changing access rights of %s to %#o failed"), temp_name,
450 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
452 /* Move temporary to its final location. */
453 if (rename (temp_name, cache_name))
454 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
455 cache_name);
457 /* Free all allocated memory. */
458 free (file_entries_new);
459 free (file_entries);
460 free (strings);
462 while (entries)
464 entry = entries;
465 entries = entries->next;
466 free (entry);
471 /* Add one library to the cache. */
472 void
473 add_to_cache (const char *path, const char *lib, int flags,
474 unsigned int osversion, uint64_t hwcap)
476 size_t liblen = strlen (lib) + 1;
477 size_t len = liblen + strlen (path) + 1;
478 struct cache_entry *new_entry
479 = xmalloc (sizeof (struct cache_entry) + liblen + len);
481 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
482 new_entry->path = new_entry->lib + liblen;
483 snprintf (new_entry->path, len, "%s/%s", path, lib);
484 new_entry->flags = flags;
485 new_entry->osversion = osversion;
486 new_entry->hwcap = hwcap;
487 new_entry->bits_hwcap = 0;
489 /* Count the number of bits set in the masked value. */
490 for (size_t i = 0;
491 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
492 if ((hwcap & (1ULL << i)) != 0)
493 ++new_entry->bits_hwcap;
496 /* Keep the list sorted - search for right place to insert. */
497 struct cache_entry *ptr = entries;
498 struct cache_entry *prev = entries;
499 while (ptr != NULL)
501 if (compare (ptr, new_entry) > 0)
502 break;
503 prev = ptr;
504 ptr = ptr->next;
506 /* Is this the first entry? */
507 if (ptr == entries)
509 new_entry->next = entries;
510 entries = new_entry;
512 else
514 new_entry->next = prev->next;
515 prev->next = new_entry;
520 /* Auxiliary cache. */
522 struct aux_cache_entry_id
524 uint64_t ino;
525 uint64_t ctime;
526 uint64_t size;
527 uint64_t dev;
530 struct aux_cache_entry
532 struct aux_cache_entry_id id;
533 int flags;
534 unsigned int osversion;
535 int used;
536 char *soname;
537 struct aux_cache_entry *next;
540 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
542 struct aux_cache_file_entry
544 struct aux_cache_entry_id id; /* Unique id of entry. */
545 int32_t flags; /* This is 1 for an ELF library. */
546 uint32_t soname; /* String table indice. */
547 uint32_t osversion; /* Required OS version. */
548 int32_t pad;
551 /* ldconfig maintains an auxiliary cache file that allows
552 only reading those libraries that have changed since the last iteration.
553 For this for each library some information is cached in the auxiliary
554 cache. */
555 struct aux_cache_file
557 char magic[sizeof AUX_CACHEMAGIC - 1];
558 uint32_t nlibs; /* Number of entries. */
559 uint32_t len_strings; /* Size of string table. */
560 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
561 /* After this the string table of size len_strings is found. */
564 static const unsigned int primes[] =
566 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
567 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
568 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
571 static size_t aux_hash_size;
572 static struct aux_cache_entry **aux_hash;
574 /* Simplistic hash function for aux_cache_entry_id. */
575 static unsigned int
576 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
578 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
579 return ret ^ (ret >> 32);
582 static size_t nextprime (size_t x)
584 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
585 if (primes[i] >= x)
586 return primes[i];
587 return x;
590 void
591 init_aux_cache (void)
593 aux_hash_size = primes[3];
594 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
598 search_aux_cache (struct stat64 *stat_buf, int *flags,
599 unsigned int *osversion, char **soname)
601 struct aux_cache_entry_id id;
602 id.ino = (uint64_t) stat_buf->st_ino;
603 id.ctime = (uint64_t) stat_buf->st_ctime;
604 id.size = (uint64_t) stat_buf->st_size;
605 id.dev = (uint64_t) stat_buf->st_dev;
607 unsigned int hash = aux_cache_entry_id_hash (&id);
608 struct aux_cache_entry *entry;
609 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
610 if (id.ino == entry->id.ino
611 && id.ctime == entry->id.ctime
612 && id.size == entry->id.size
613 && id.dev == entry->id.dev)
615 *flags = entry->flags;
616 *osversion = entry->osversion;
617 if (entry->soname != NULL)
618 *soname = xstrdup (entry->soname);
619 else
620 *soname = NULL;
621 entry->used = 1;
622 return 1;
625 return 0;
628 static void
629 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
630 unsigned int osversion, const char *soname, int used)
632 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
633 struct aux_cache_entry *entry;
634 for (entry = aux_hash[hash]; entry; entry = entry->next)
635 if (id->ino == entry->id.ino
636 && id->ctime == entry->id.ctime
637 && id->size == entry->id.size
638 && id->dev == entry->id.dev)
639 abort ();
641 size_t len = soname ? strlen (soname) + 1 : 0;
642 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
643 entry->id = *id;
644 entry->flags = flags;
645 entry->osversion = osversion;
646 entry->used = used;
647 if (soname != NULL)
648 entry->soname = memcpy ((char *) (entry + 1), soname, len);
649 else
650 entry->soname = NULL;
651 entry->next = aux_hash[hash];
652 aux_hash[hash] = entry;
655 void
656 add_to_aux_cache (struct stat64 *stat_buf, int flags,
657 unsigned int osversion, const char *soname)
659 struct aux_cache_entry_id id;
660 id.ino = (uint64_t) stat_buf->st_ino;
661 id.ctime = (uint64_t) stat_buf->st_ctime;
662 id.size = (uint64_t) stat_buf->st_size;
663 id.dev = (uint64_t) stat_buf->st_dev;
664 insert_to_aux_cache (&id, flags, osversion, soname, 1);
667 /* Load auxiliary cache to search for unchanged entries. */
668 void
669 load_aux_cache (const char *aux_cache_name)
671 int fd = open (aux_cache_name, O_RDONLY);
672 if (fd < 0)
674 init_aux_cache ();
675 return;
678 struct stat64 st;
679 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
681 close (fd);
682 init_aux_cache ();
683 return;
686 size_t aux_cache_size = st.st_size;
687 struct aux_cache_file *aux_cache
688 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
689 if (aux_cache == MAP_FAILED
690 || aux_cache_size < sizeof (struct aux_cache_file)
691 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
692 || aux_cache->nlibs >= aux_cache_size)
694 close (fd);
695 init_aux_cache ();
696 return;
699 aux_hash_size = nextprime (aux_cache->nlibs);
700 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
702 const char *aux_cache_data
703 = (const char *) &aux_cache->libs[aux_cache->nlibs];
704 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
705 insert_to_aux_cache (&aux_cache->libs[i].id,
706 aux_cache->libs[i].flags,
707 aux_cache->libs[i].osversion,
708 aux_cache->libs[i].soname == 0
709 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
712 munmap (aux_cache, aux_cache_size);
713 close (fd);
716 /* Save the contents of the auxiliary cache. */
717 void
718 save_aux_cache (const char *aux_cache_name)
720 /* Count the length of all sonames. We start with empty string. */
721 size_t total_strlen = 1;
722 /* Number of cache entries. */
723 int cache_entry_count = 0;
725 for (size_t i = 0; i < aux_hash_size; ++i)
726 for (struct aux_cache_entry *entry = aux_hash[i];
727 entry != NULL; entry = entry->next)
728 if (entry->used)
730 ++cache_entry_count;
731 if (entry->soname != NULL)
732 total_strlen += strlen (entry->soname) + 1;
735 /* Auxiliary cache. */
736 size_t file_entries_size
737 = sizeof (struct aux_cache_file)
738 + cache_entry_count * sizeof (struct aux_cache_file_entry);
739 struct aux_cache_file *file_entries
740 = xmalloc (file_entries_size + total_strlen);
742 /* Fill in the header of the auxiliary cache. */
743 memset (file_entries, '\0', sizeof (struct aux_cache_file));
744 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
746 file_entries->nlibs = cache_entry_count;
747 file_entries->len_strings = total_strlen;
749 /* Initial String offset for auxiliary cache is always after the
750 special empty string. */
751 unsigned int str_offset = 1;
753 /* An array for all strings. */
754 char *str = (char *) file_entries + file_entries_size;
755 *str++ = '\0';
757 size_t idx = 0;
758 for (size_t i = 0; i < aux_hash_size; ++i)
759 for (struct aux_cache_entry *entry = aux_hash[i];
760 entry != NULL; entry = entry->next)
761 if (entry->used)
763 file_entries->libs[idx].id = entry->id;
764 file_entries->libs[idx].flags = entry->flags;
765 if (entry->soname == NULL)
766 file_entries->libs[idx].soname = 0;
767 else
769 file_entries->libs[idx].soname = str_offset;
771 size_t len = strlen (entry->soname) + 1;
772 str = mempcpy (str, entry->soname, len);
773 str_offset += len;
775 file_entries->libs[idx].osversion = entry->osversion;
776 file_entries->libs[idx++].pad = 0;
779 /* Write out auxiliary cache file. */
780 /* Write auxiliary cache first to a temporary file and rename it later. */
782 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
783 sprintf (temp_name, "%s~", aux_cache_name);
785 /* Check that directory exists and create if needed. */
786 char *dir = strdupa (aux_cache_name);
787 dir = dirname (dir);
789 struct stat64 st;
790 if (stat64 (dir, &st) < 0)
792 if (mkdir (dir, 0700) < 0)
793 goto out_fail;
796 /* Create file. */
797 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
798 S_IRUSR|S_IWUSR);
799 if (fd < 0)
800 goto out_fail;
802 if (write (fd, file_entries, file_entries_size + total_strlen)
803 != (ssize_t) (file_entries_size + total_strlen)
804 || close (fd))
806 unlink (temp_name);
807 goto out_fail;
810 /* Move temporary to its final location. */
811 if (rename (temp_name, aux_cache_name))
812 unlink (temp_name);
814 out_fail:
815 /* Free allocated memory. */
816 free (temp_name);
817 free (file_entries);