]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/cache.c
Merge branch release/2.28/master into ibm/2.28/master
[thirdparty/glibc.git] / elf / cache.c
CommitLineData
688903eb 1/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
591e1ffb
UD
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
4
43bc8ac6 5 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
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.
591e1ffb 9
43bc8ac6 10 This program is distributed in the hope that it will be useful,
591e1ffb 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
591e1ffb 14
43bc8ac6 15 You should have received a copy of the GNU General Public License
59ba27a6 16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
591e1ffb 17
591e1ffb
UD
18#include <errno.h>
19#include <error.h>
20#include <dirent.h>
68162753 21#include <inttypes.h>
27d9ffda 22#include <libgen.h>
591e1ffb
UD
23#include <libintl.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
e054f494 28#include <stdint.h>
591e1ffb
UD
29#include <sys/fcntl.h>
30#include <sys/mman.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33
8f480b4b
RM
34#include <ldconfig.h>
35#include <dl-cache.h>
591e1ffb
UD
36
37struct cache_entry
38{
45eca4d1
UD
39 char *lib; /* Library name. */
40 char *path; /* Path to find library. */
41 int flags; /* Flags to indicate kind of library. */
a986484f 42 unsigned int osversion; /* Required OS version. */
ad1a5cc7 43 uint64_t hwcap; /* Important hardware capabilities. */
45eca4d1
UD
44 int bits_hwcap; /* Number of bits set in hwcap. */
45 struct cache_entry *next; /* Next entry in list. */
591e1ffb
UD
46};
47
591e1ffb
UD
48/* List of all cache entries. */
49static struct cache_entry *entries;
50
51static const char *flag_descr[] =
52{ "libc4", "ELF", "libc5", "libc6"};
53
591e1ffb
UD
54/* Print a single entry. */
55static void
a986484f
UD
56print_entry (const char *lib, int flag, unsigned int osversion,
57 uint64_t hwcap, const char *key)
591e1ffb
UD
58{
59 printf ("\t%s (", lib);
0b7219cc 60 switch (flag & FLAG_TYPE_MASK)
591e1ffb
UD
61 {
62 case FLAG_LIBC4:
63 case FLAG_ELF:
64 case FLAG_ELF_LIBC5:
65 case FLAG_ELF_LIBC6:
a986484f 66 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
591e1ffb
UD
67 break;
68 default:
96c0d65d 69 fputs (_("unknown"), stdout);
591e1ffb
UD
70 break;
71 }
72 switch (flag & FLAG_REQUIRED_MASK)
73 {
591e1ffb
UD
74 case FLAG_SPARC_LIB64:
75 fputs (",64bit", stdout);
48c53070 76 break;
95582174
UD
77 case FLAG_IA64_LIB64:
78 fputs (",IA-64", stdout);
fdedb42e 79 break;
fdedb42e
AJ
80 case FLAG_X8664_LIB64:
81 fputs (",x86-64", stdout);
82 break;
96c0d65d 83 case FLAG_S390_LIB64:
27d9ffda 84 fputs (",64bit", stdout);
48c53070
RM
85 break;
86 case FLAG_POWERPC_LIB64:
27d9ffda 87 fputs (",64bit", stdout);
48c53070 88 break;
b5bac573 89 case FLAG_MIPS64_LIBN32:
27d9ffda 90 fputs (",N32", stdout);
b5bac573
AO
91 break;
92 case FLAG_MIPS64_LIBN64:
27d9ffda 93 fputs (",64bit", stdout);
f1a77b01
L
94 break;
95 case FLAG_X8664_LIBX32:
96 fputs (",x32", stdout);
97 break;
6665d4a2
SM
98 case FLAG_ARM_LIBHF:
99 fputs (",hard-float", stdout);
100 break;
1f51ee92
SM
101 case FLAG_AARCH64_LIB64:
102 fputs (",AArch64", stdout);
103 break;
b39949d2
CD
104 /* Uses the ARM soft-float ABI. */
105 case FLAG_ARM_LIBSF:
106 fputs (",soft-float", stdout);
107 break;
9c21573c
MR
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;
fb58aac5
PD
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;
591e1ffb
UD
123 case 0:
124 break;
125 default:
45eca4d1 126 printf (",%d", flag & FLAG_REQUIRED_MASK);
591e1ffb
UD
127 break;
128 }
45eca4d1 129 if (hwcap != 0)
ab1d521d 130 printf (", hwcap: %#.16" PRIx64, hwcap);
a986484f
UD
131 if (osversion != 0)
132 {
133 static const char *const abi_tag_os[] =
134 {
135 [0] = "Linux",
136 [1] = "Hurd",
137 [2] = "Solaris",
82c26126 138 [3] = "FreeBSD",
ae0d550c 139 [4] = "kNetBSD",
8e856b5a
RM
140 [5] = "Syllable",
141 [6] = N_("Unknown OS")
a986484f 142 };
82c26126 143#define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
a986484f
UD
144 unsigned int os = osversion >> 24;
145
96c0d65d 146 printf (_(", OS ABI: %s %d.%d.%d"),
82c26126 147 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
a986484f
UD
148 (osversion >> 16) & 0xff,
149 (osversion >> 8) & 0xff,
150 osversion & 0xff);
151 }
591e1ffb
UD
152 printf (") => %s\n", key);
153}
154
155
45eca4d1
UD
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. */
591e1ffb
UD
158void
159print_cache (const char *cache_name)
160{
27d9ffda 161 int fd = open (cache_name, O_RDONLY);
591e1ffb
UD
162 if (fd < 0)
163 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
164
27d9ffda 165 struct stat64 st;
b4a555d6 166 if (fstat64 (fd, &st) < 0
591e1ffb
UD
167 /* No need to map the file if it is empty. */
168 || st.st_size == 0)
169 {
170 close (fd);
171 return;
172 }
25ee87d6 173
27d9ffda
UD
174 struct cache_file *cache
175 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
591e1ffb
UD
176 if (cache == MAP_FAILED)
177 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
591e1ffb 178
27d9ffda 179 size_t cache_size = st.st_size;
45eca4d1
UD
180 if (cache_size < sizeof (struct cache_file))
181 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
182
27d9ffda
UD
183 struct cache_file_new *cache_new = NULL;
184 const char *cache_data;
185 int format = 0;
186
45eca4d1
UD
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. */
e25054c4 198 cache_data = (const char *) cache_new;
45eca4d1
UD
199 }
200 else
201 {
e25054c4 202 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
a986484f
UD
203 + (cache->nlibs
204 * sizeof (struct file_entry)));
45eca4d1
UD
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 >
e25054c4 210 (offset + sizeof (struct cache_file_new)))
45eca4d1 211 {
e25054c4
AJ
212
213 cache_new = (struct cache_file_new *) ((void *)cache + offset);
591e1ffb 214
a986484f
UD
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)
e25054c4
AJ
219 {
220 cache_data = (const char *) cache_new;
221 format = 1;
222 }
45eca4d1
UD
223 }
224 }
25ee87d6 225
45eca4d1
UD
226 if (format == 0)
227 {
228 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
591e1ffb 229
45eca4d1 230 /* Print everything. */
27d9ffda 231 for (unsigned int i = 0; i < cache->nlibs; i++)
45eca4d1 232 print_entry (cache_data + cache->libs[i].key,
a986484f 233 cache->libs[i].flags, 0, 0,
45eca4d1
UD
234 cache_data + cache->libs[i].value);
235 }
236 else if (format == 1)
237 {
a986484f
UD
238 printf (_("%d libs found in cache `%s'\n"),
239 cache_new->nlibs, cache_name);
45eca4d1
UD
240
241 /* Print everything. */
27d9ffda 242 for (unsigned int i = 0; i < cache_new->nlibs; i++)
45eca4d1
UD
243 print_entry (cache_data + cache_new->libs[i].key,
244 cache_new->libs[i].flags,
a986484f 245 cache_new->libs[i].osversion,
45eca4d1
UD
246 cache_new->libs[i].hwcap,
247 cache_data + cache_new->libs[i].value);
248 }
591e1ffb
UD
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
27d9ffda
UD
261static int
262compare (const struct cache_entry *e1, const struct cache_entry *e2)
591e1ffb 263{
591e1ffb 264 /* We need to swap entries here to get the correct sort order. */
27d9ffda 265 int res = _dl_cache_libcmp (e2->lib, e1->lib);
591e1ffb
UD
266 if (res == 0)
267 {
268 if (e1->flags < e2->flags)
269 return 1;
270 else if (e1->flags > e2->flags)
271 return -1;
45eca4d1
UD
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;
a986484f
UD
281 if (e2->osversion > e1->osversion)
282 return 1;
283 if (e2->osversion < e1->osversion)
284 return -1;
591e1ffb
UD
285 }
286 return res;
287}
288
591e1ffb
UD
289/* Save the contents of the cache. */
290void
291save_cache (const char *cache_name)
292{
591e1ffb
UD
293 /* The cache entries are sorted already, save them in this order. */
294
295 /* Count the length of all strings. */
45eca4d1
UD
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. */
27d9ffda
UD
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
591e1ffb
UD
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;
45eca4d1
UD
311 if (entry->hwcap == 0)
312 ++cache_entry_old_count;
591e1ffb 313 }
25ee87d6 314
591e1ffb 315 /* Create the on disk cache structure. */
27d9ffda
UD
316 struct cache_file *file_entries = NULL;
317 size_t file_entries_size = 0;
591e1ffb 318
45eca4d1
UD
319 if (opt_format != 2)
320 {
062df960
UD
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
45eca4d1
UD
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);
27d9ffda 331 file_entries = xmalloc (file_entries_size);
45eca4d1
UD
332
333 /* Fill in the header. */
27d9ffda 334 memset (file_entries, '\0', sizeof (struct cache_file));
45eca4d1 335 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
591e1ffb 336
45eca4d1
UD
337 file_entries->nlibs = cache_entry_old_count;
338 }
25ee87d6 339
27d9ffda
UD
340 struct cache_file_new *file_entries_new = NULL;
341 size_t file_entries_new_size = 0;
342
45eca4d1
UD
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);
27d9ffda 348 file_entries_new = xmalloc (file_entries_new_size);
45eca4d1
UD
349
350 /* Fill in the header. */
27d9ffda 351 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
a986484f
UD
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);
45eca4d1
UD
356
357 file_entries_new->nlibs = cache_entry_count;
358 file_entries_new->len_strings = total_strlen;
359 }
95582174 360
27d9ffda
UD
361 /* Pad for alignment of cache_file_new. */
362 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
95582174 363
45eca4d1
UD
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. */
27d9ffda 367 unsigned int str_offset;
e25054c4 368 if (opt_format != 0)
45eca4d1
UD
369 str_offset = file_entries_new_size;
370 else
371 str_offset = 0;
591e1ffb 372
27d9ffda
UD
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
45eca4d1
UD
379 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
380 entry = entry->next, ++idx_new)
591e1ffb 381 {
591e1ffb 382 /* First the library. */
062df960 383 if (opt_format != 2 && entry->hwcap == 0)
45eca4d1
UD
384 {
385 file_entries->libs[idx_old].flags = entry->flags;
386 /* XXX: Actually we can optimize here and remove duplicates. */
e25054c4 387 file_entries->libs[idx_old].key = str_offset + pad;
45eca4d1
UD
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
ded5b9b7 393 always begins at the beginning of the new cache
45eca4d1
UD
394 struct. */
395 file_entries_new->libs[idx_new].flags = entry->flags;
a986484f 396 file_entries_new->libs[idx_new].osversion = entry->osversion;
45eca4d1
UD
397 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
398 file_entries_new->libs[idx_new].key = str_offset;
399 }
27d9ffda
UD
400
401 size_t len = strlen (entry->lib) + 1;
402 str = mempcpy (str, entry->lib, len);
403 str_offset += len;
591e1ffb 404 /* Then the path. */
062df960 405 if (opt_format != 2 && entry->hwcap == 0)
e25054c4 406 file_entries->libs[idx_old].value = str_offset + pad;
45eca4d1
UD
407 if (opt_format != 0)
408 file_entries_new->libs[idx_new].value = str_offset;
27d9ffda
UD
409 len = strlen (entry->path) + 1;
410 str = mempcpy (str, entry->path, len);
411 str_offset += len;
45eca4d1
UD
412 /* Ignore entries with hwcap for old format. */
413 if (entry->hwcap == 0)
414 ++idx_old;
591e1ffb 415 }
591e1ffb 416
062df960
UD
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
591e1ffb
UD
422 /* Write out the cache. */
423
424 /* Write cache first to a temporary file and rename it later. */
27d9ffda 425 char *temp_name = xmalloc (strlen (cache_name) + 2);
591e1ffb 426 sprintf (temp_name, "%s~", cache_name);
591e1ffb
UD
427
428 /* Create file. */
27d9ffda
UD
429 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
430 S_IRUSR|S_IWUSR);
591e1ffb
UD
431 if (fd < 0)
432 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
433 temp_name);
434
435 /* Write contents. */
45eca4d1
UD
436 if (opt_format != 2)
437 {
a986484f 438 if (write (fd, file_entries, file_entries_size)
0292b0dd 439 != (ssize_t) file_entries_size)
45eca4d1
UD
440 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
441 }
442 if (opt_format != 0)
443 {
e25054c4
AJ
444 /* Align cache. */
445 if (opt_format != 2)
446 {
a986484f 447 char zero[pad];
0292b0dd
UD
448 memset (zero, '\0', pad);
449 if (write (fd, zero, pad) != (ssize_t) pad)
e25054c4
AJ
450 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
451 }
45eca4d1 452 if (write (fd, file_entries_new, file_entries_new_size)
0292b0dd 453 != (ssize_t) file_entries_new_size)
45eca4d1
UD
454 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
455 }
591e1ffb 456
999a6dab 457 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
11bf311e 458 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
591e1ffb 459
25ee87d6 460 /* Make sure user can always read cache file */
ba9fcb3f 461 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
25ee87d6 462 error (EXIT_FAILURE, errno,
ba9fcb3f
UD
463 _("Changing access rights of %s to %#o failed"), temp_name,
464 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
25ee87d6 465
999a6dab
FW
466 /* Make sure that data is written to disk. */
467 if (fsync (fd) != 0 || close (fd) != 0)
468 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
469
591e1ffb
UD
470 /* Move temporary to its final location. */
471 if (rename (temp_name, cache_name))
472 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
473 cache_name);
25ee87d6 474
591e1ffb 475 /* Free all allocated memory. */
0292b0dd 476 free (file_entries_new);
591e1ffb
UD
477 free (file_entries);
478 free (strings);
479
480 while (entries)
481 {
482 entry = entries;
591e1ffb
UD
483 entries = entries->next;
484 free (entry);
485 }
486}
487
45eca4d1 488
591e1ffb
UD
489/* Add one library to the cache. */
490void
45eca4d1 491add_to_cache (const char *path, const char *lib, int flags,
a986484f 492 unsigned int osversion, uint64_t hwcap)
591e1ffb 493{
27d9ffda
UD
494 size_t liblen = strlen (lib) + 1;
495 size_t len = liblen + strlen (path) + 1;
496 struct cache_entry *new_entry
497 = xmalloc (sizeof (struct cache_entry) + liblen + len);
498
499 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
500 new_entry->path = new_entry->lib + liblen;
501 snprintf (new_entry->path, len, "%s/%s", path, lib);
591e1ffb 502 new_entry->flags = flags;
a986484f 503 new_entry->osversion = osversion;
45eca4d1
UD
504 new_entry->hwcap = hwcap;
505 new_entry->bits_hwcap = 0;
506
507 /* Count the number of bits set in the masked value. */
27d9ffda
UD
508 for (size_t i = 0;
509 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
ad1a5cc7 510 if ((hwcap & (1ULL << i)) != 0)
45eca4d1
UD
511 ++new_entry->bits_hwcap;
512
591e1ffb
UD
513
514 /* Keep the list sorted - search for right place to insert. */
27d9ffda
UD
515 struct cache_entry *ptr = entries;
516 struct cache_entry *prev = entries;
591e1ffb
UD
517 while (ptr != NULL)
518 {
519 if (compare (ptr, new_entry) > 0)
520 break;
521 prev = ptr;
522 ptr = ptr->next;
523 }
524 /* Is this the first entry? */
525 if (ptr == entries)
526 {
527 new_entry->next = entries;
528 entries = new_entry;
529 }
530 else
531 {
532 new_entry->next = prev->next;
533 prev->next = new_entry;
534 }
535}
27d9ffda
UD
536
537
538/* Auxiliary cache. */
539
540struct aux_cache_entry_id
541{
542 uint64_t ino;
543 uint64_t ctime;
544 uint64_t size;
545 uint64_t dev;
546};
547
548struct aux_cache_entry
549{
550 struct aux_cache_entry_id id;
551 int flags;
552 unsigned int osversion;
553 int used;
554 char *soname;
555 struct aux_cache_entry *next;
556};
557
558#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
559
560struct aux_cache_file_entry
561{
562 struct aux_cache_entry_id id; /* Unique id of entry. */
563 int32_t flags; /* This is 1 for an ELF library. */
564 uint32_t soname; /* String table indice. */
565 uint32_t osversion; /* Required OS version. */
566 int32_t pad;
567};
568
569/* ldconfig maintains an auxiliary cache file that allows
570 only reading those libraries that have changed since the last iteration.
571 For this for each library some information is cached in the auxiliary
572 cache. */
573struct aux_cache_file
574{
575 char magic[sizeof AUX_CACHEMAGIC - 1];
576 uint32_t nlibs; /* Number of entries. */
577 uint32_t len_strings; /* Size of string table. */
578 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
579 /* After this the string table of size len_strings is found. */
580};
581
3c87d79d 582static const unsigned int primes[] =
27d9ffda
UD
583{
584 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
585 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
586 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
587};
588
589static size_t aux_hash_size;
590static struct aux_cache_entry **aux_hash;
591
592/* Simplistic hash function for aux_cache_entry_id. */
593static unsigned int
594aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
595{
596 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
597 return ret ^ (ret >> 32);
598}
599
600static size_t nextprime (size_t x)
601{
602 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
603 if (primes[i] >= x)
604 return primes[i];
605 return x;
606}
607
608void
609init_aux_cache (void)
610{
611 aux_hash_size = primes[3];
612 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
613}
614
615int
616search_aux_cache (struct stat64 *stat_buf, int *flags,
617 unsigned int *osversion, char **soname)
618{
619 struct aux_cache_entry_id id;
620 id.ino = (uint64_t) stat_buf->st_ino;
621 id.ctime = (uint64_t) stat_buf->st_ctime;
622 id.size = (uint64_t) stat_buf->st_size;
623 id.dev = (uint64_t) stat_buf->st_dev;
624
625 unsigned int hash = aux_cache_entry_id_hash (&id);
626 struct aux_cache_entry *entry;
627 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
628 if (id.ino == entry->id.ino
629 && id.ctime == entry->id.ctime
630 && id.size == entry->id.size
631 && id.dev == entry->id.dev)
632 {
633 *flags = entry->flags;
634 *osversion = entry->osversion;
635 if (entry->soname != NULL)
636 *soname = xstrdup (entry->soname);
637 else
638 *soname = NULL;
639 entry->used = 1;
640 return 1;
641 }
642
643 return 0;
644}
645
646static void
647insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
648 unsigned int osversion, const char *soname, int used)
649{
650 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
651 struct aux_cache_entry *entry;
652 for (entry = aux_hash[hash]; entry; entry = entry->next)
653 if (id->ino == entry->id.ino
654 && id->ctime == entry->id.ctime
655 && id->size == entry->id.size
656 && id->dev == entry->id.dev)
657 abort ();
658
659 size_t len = soname ? strlen (soname) + 1 : 0;
660 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
661 entry->id = *id;
662 entry->flags = flags;
663 entry->osversion = osversion;
664 entry->used = used;
665 if (soname != NULL)
666 entry->soname = memcpy ((char *) (entry + 1), soname, len);
667 else
668 entry->soname = NULL;
669 entry->next = aux_hash[hash];
670 aux_hash[hash] = entry;
671}
672
673void
674add_to_aux_cache (struct stat64 *stat_buf, int flags,
675 unsigned int osversion, const char *soname)
676{
677 struct aux_cache_entry_id id;
678 id.ino = (uint64_t) stat_buf->st_ino;
679 id.ctime = (uint64_t) stat_buf->st_ctime;
680 id.size = (uint64_t) stat_buf->st_size;
681 id.dev = (uint64_t) stat_buf->st_dev;
682 insert_to_aux_cache (&id, flags, osversion, soname, 1);
683}
684
685/* Load auxiliary cache to search for unchanged entries. */
686void
687load_aux_cache (const char *aux_cache_name)
688{
689 int fd = open (aux_cache_name, O_RDONLY);
690 if (fd < 0)
691 {
692 init_aux_cache ();
693 return;
694 }
695
696 struct stat64 st;
697 if (fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
698 {
699 close (fd);
700 init_aux_cache ();
701 return;
702 }
703
704 size_t aux_cache_size = st.st_size;
705 struct aux_cache_file *aux_cache
706 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
707 if (aux_cache == MAP_FAILED
708 || aux_cache_size < sizeof (struct aux_cache_file)
709 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
6a1cf708
AJ
710 || aux_cache_size != (sizeof(struct aux_cache_file) +
711 aux_cache->nlibs * sizeof(struct aux_cache_file_entry) +
712 aux_cache->len_strings))
27d9ffda
UD
713 {
714 close (fd);
715 init_aux_cache ();
716 return;
717 }
718
719 aux_hash_size = nextprime (aux_cache->nlibs);
720 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
721
722 const char *aux_cache_data
723 = (const char *) &aux_cache->libs[aux_cache->nlibs];
724 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
725 insert_to_aux_cache (&aux_cache->libs[i].id,
726 aux_cache->libs[i].flags,
727 aux_cache->libs[i].osversion,
728 aux_cache->libs[i].soname == 0
729 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
730 0);
731
732 munmap (aux_cache, aux_cache_size);
733 close (fd);
734}
735
736/* Save the contents of the auxiliary cache. */
737void
738save_aux_cache (const char *aux_cache_name)
739{
740 /* Count the length of all sonames. We start with empty string. */
741 size_t total_strlen = 1;
742 /* Number of cache entries. */
743 int cache_entry_count = 0;
744
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 ++cache_entry_count;
751 if (entry->soname != NULL)
752 total_strlen += strlen (entry->soname) + 1;
753 }
754
755 /* Auxiliary cache. */
756 size_t file_entries_size
757 = sizeof (struct aux_cache_file)
758 + cache_entry_count * sizeof (struct aux_cache_file_entry);
759 struct aux_cache_file *file_entries
760 = xmalloc (file_entries_size + total_strlen);
761
762 /* Fill in the header of the auxiliary cache. */
763 memset (file_entries, '\0', sizeof (struct aux_cache_file));
764 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
765
766 file_entries->nlibs = cache_entry_count;
767 file_entries->len_strings = total_strlen;
768
769 /* Initial String offset for auxiliary cache is always after the
770 special empty string. */
771 unsigned int str_offset = 1;
772
773 /* An array for all strings. */
774 char *str = (char *) file_entries + file_entries_size;
775 *str++ = '\0';
776
777 size_t idx = 0;
778 for (size_t i = 0; i < aux_hash_size; ++i)
779 for (struct aux_cache_entry *entry = aux_hash[i];
780 entry != NULL; entry = entry->next)
781 if (entry->used)
782 {
783 file_entries->libs[idx].id = entry->id;
784 file_entries->libs[idx].flags = entry->flags;
785 if (entry->soname == NULL)
786 file_entries->libs[idx].soname = 0;
787 else
788 {
789 file_entries->libs[idx].soname = str_offset;
790
791 size_t len = strlen (entry->soname) + 1;
792 str = mempcpy (str, entry->soname, len);
793 str_offset += len;
794 }
795 file_entries->libs[idx].osversion = entry->osversion;
796 file_entries->libs[idx++].pad = 0;
797 }
798
799 /* Write out auxiliary cache file. */
800 /* Write auxiliary cache first to a temporary file and rename it later. */
801
802 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
803 sprintf (temp_name, "%s~", aux_cache_name);
804
805 /* Check that directory exists and create if needed. */
806 char *dir = strdupa (aux_cache_name);
807 dir = dirname (dir);
808
809 struct stat64 st;
810 if (stat64 (dir, &st) < 0)
811 {
812 if (mkdir (dir, 0700) < 0)
813 goto out_fail;
814 }
815
816 /* Create file. */
817 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
818 S_IRUSR|S_IWUSR);
819 if (fd < 0)
820 goto out_fail;
821
822 if (write (fd, file_entries, file_entries_size + total_strlen)
823 != (ssize_t) (file_entries_size + total_strlen)
999a6dab
FW
824 || fdatasync (fd) != 0
825 || close (fd) != 0)
27d9ffda
UD
826 {
827 unlink (temp_name);
828 goto out_fail;
829 }
830
831 /* Move temporary to its final location. */
832 if (rename (temp_name, aux_cache_name))
833 unlink (temp_name);
834
835out_fail:
836 /* Free allocated memory. */
78d6dd72 837 free (temp_name);
27d9ffda
UD
838 free (file_entries);
839}