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