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