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