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