]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/cache.c
elf: Implement a string table for ldconfig, with tail merging
[thirdparty/glibc.git] / elf / cache.c
CommitLineData
d614a753 1/* Copyright (C) 1999-2020 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
5a82c748 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
591e1ffb 17
dfb3f101 18#include <assert.h>
591e1ffb
UD
19#include <errno.h>
20#include <error.h>
21#include <dirent.h>
68162753 22#include <inttypes.h>
27d9ffda 23#include <libgen.h>
591e1ffb
UD
24#include <libintl.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
e054f494 29#include <stdint.h>
591e1ffb
UD
30#include <sys/fcntl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/types.h>
34
8f480b4b
RM
35#include <ldconfig.h>
36#include <dl-cache.h>
dfb3f101 37#include <version.h>
591e1ffb
UD
38
39struct cache_entry
40{
45eca4d1
UD
41 char *lib; /* Library name. */
42 char *path; /* Path to find library. */
43 int flags; /* Flags to indicate kind of library. */
a986484f 44 unsigned int osversion; /* Required OS version. */
ad1a5cc7 45 uint64_t hwcap; /* Important hardware capabilities. */
45eca4d1
UD
46 int bits_hwcap; /* Number of bits set in hwcap. */
47 struct cache_entry *next; /* Next entry in list. */
591e1ffb
UD
48};
49
591e1ffb
UD
50/* List of all cache entries. */
51static struct cache_entry *entries;
52
53static const char *flag_descr[] =
54{ "libc4", "ELF", "libc5", "libc6"};
55
591e1ffb
UD
56/* Print a single entry. */
57static void
a986484f
UD
58print_entry (const char *lib, int flag, unsigned int osversion,
59 uint64_t hwcap, const char *key)
591e1ffb
UD
60{
61 printf ("\t%s (", lib);
0b7219cc 62 switch (flag & FLAG_TYPE_MASK)
591e1ffb
UD
63 {
64 case FLAG_LIBC4:
65 case FLAG_ELF:
66 case FLAG_ELF_LIBC5:
67 case FLAG_ELF_LIBC6:
a986484f 68 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
591e1ffb
UD
69 break;
70 default:
96c0d65d 71 fputs (_("unknown"), stdout);
591e1ffb
UD
72 break;
73 }
74 switch (flag & FLAG_REQUIRED_MASK)
75 {
591e1ffb
UD
76 case FLAG_SPARC_LIB64:
77 fputs (",64bit", stdout);
48c53070 78 break;
95582174
UD
79 case FLAG_IA64_LIB64:
80 fputs (",IA-64", stdout);
fdedb42e 81 break;
fdedb42e
AJ
82 case FLAG_X8664_LIB64:
83 fputs (",x86-64", stdout);
84 break;
96c0d65d 85 case FLAG_S390_LIB64:
27d9ffda 86 fputs (",64bit", stdout);
48c53070
RM
87 break;
88 case FLAG_POWERPC_LIB64:
27d9ffda 89 fputs (",64bit", stdout);
48c53070 90 break;
b5bac573 91 case FLAG_MIPS64_LIBN32:
27d9ffda 92 fputs (",N32", stdout);
b5bac573
AO
93 break;
94 case FLAG_MIPS64_LIBN64:
27d9ffda 95 fputs (",64bit", stdout);
f1a77b01
L
96 break;
97 case FLAG_X8664_LIBX32:
98 fputs (",x32", stdout);
99 break;
6665d4a2
SM
100 case FLAG_ARM_LIBHF:
101 fputs (",hard-float", stdout);
102 break;
1f51ee92
SM
103 case FLAG_AARCH64_LIB64:
104 fputs (",AArch64", stdout);
105 break;
b39949d2
CD
106 /* Uses the ARM soft-float ABI. */
107 case FLAG_ARM_LIBSF:
108 fputs (",soft-float", stdout);
109 break;
9c21573c
MR
110 case FLAG_MIPS_LIB32_NAN2008:
111 fputs (",nan2008", stdout);
112 break;
113 case FLAG_MIPS64_LIBN32_NAN2008:
114 fputs (",N32,nan2008", stdout);
115 break;
116 case FLAG_MIPS64_LIBN64_NAN2008:
117 fputs (",64bit,nan2008", stdout);
118 break;
fb58aac5
PD
119 case FLAG_RISCV_FLOAT_ABI_SOFT:
120 fputs (",soft-float", stdout);
121 break;
122 case FLAG_RISCV_FLOAT_ABI_DOUBLE:
123 fputs (",double-float", stdout);
124 break;
591e1ffb
UD
125 case 0:
126 break;
127 default:
45eca4d1 128 printf (",%d", flag & FLAG_REQUIRED_MASK);
591e1ffb
UD
129 break;
130 }
45eca4d1 131 if (hwcap != 0)
ab1d521d 132 printf (", hwcap: %#.16" PRIx64, hwcap);
a986484f
UD
133 if (osversion != 0)
134 {
135 static const char *const abi_tag_os[] =
136 {
137 [0] = "Linux",
138 [1] = "Hurd",
139 [2] = "Solaris",
82c26126 140 [3] = "FreeBSD",
ae0d550c 141 [4] = "kNetBSD",
8e856b5a
RM
142 [5] = "Syllable",
143 [6] = N_("Unknown OS")
a986484f 144 };
82c26126 145#define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
a986484f
UD
146 unsigned int os = osversion >> 24;
147
96c0d65d 148 printf (_(", OS ABI: %s %d.%d.%d"),
82c26126 149 _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
a986484f
UD
150 (osversion >> 16) & 0xff,
151 (osversion >> 8) & 0xff,
152 osversion & 0xff);
153 }
591e1ffb
UD
154 printf (") => %s\n", key);
155}
156
84ba719b
FW
157/* Print an error and exit if the new-file cache is internally
158 inconsistent. */
159static void
160check_new_cache (struct cache_file_new *cache)
161{
162 if (! cache_file_new_matches_endian (cache))
163 error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
164}
591e1ffb 165
dfb3f101
FW
166/* Print the extension information at the cache at start address
167 FILE_BASE, of length FILE_SIZE bytes. The new-format cache header
168 is at CACHE, and the file name for diagnostics is CACHE_NAME. */
169static void
170print_extensions (struct cache_extension_all_loaded *ext)
171{
172 if (ext->sections[cache_extension_tag_generator].base != NULL)
173 {
174 fputs (_("Cache generated by: "), stdout);
175 fwrite (ext->sections[cache_extension_tag_generator].base, 1,
176 ext->sections[cache_extension_tag_generator].size, stdout);
177 putchar ('\n');
178 }
179}
180
45eca4d1
UD
181/* Print the whole cache file, if a file contains the new cache format
182 hidden in the old one, print the contents of the new format. */
591e1ffb
UD
183void
184print_cache (const char *cache_name)
185{
27d9ffda 186 int fd = open (cache_name, O_RDONLY);
591e1ffb
UD
187 if (fd < 0)
188 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
189
27d9ffda 190 struct stat64 st;
04986243 191 if (__fstat64 (fd, &st) < 0
591e1ffb
UD
192 /* No need to map the file if it is empty. */
193 || st.st_size == 0)
194 {
195 close (fd);
196 return;
197 }
25ee87d6 198
27d9ffda
UD
199 struct cache_file *cache
200 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
591e1ffb
UD
201 if (cache == MAP_FAILED)
202 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
591e1ffb 203
27d9ffda 204 size_t cache_size = st.st_size;
45eca4d1
UD
205 if (cache_size < sizeof (struct cache_file))
206 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
207
27d9ffda
UD
208 struct cache_file_new *cache_new = NULL;
209 const char *cache_data;
210 int format = 0;
211
45eca4d1
UD
212 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
213 {
214 /* This can only be the new format without the old one. */
215 cache_new = (struct cache_file_new *) cache;
216
217 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
218 || memcmp (cache_new->version, CACHE_VERSION,
219 sizeof CACHE_VERSION - 1))
220 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
84ba719b 221 check_new_cache (cache_new);
45eca4d1
UD
222 format = 1;
223 /* This is where the strings start. */
e25054c4 224 cache_data = (const char *) cache_new;
45eca4d1
UD
225 }
226 else
227 {
2954daf0
AS
228 /* Check for corruption, avoiding overflow. */
229 if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry)
230 < cache->nlibs)
231 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
232
e25054c4 233 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
a986484f
UD
234 + (cache->nlibs
235 * sizeof (struct file_entry)));
45eca4d1
UD
236 /* This is where the strings start. */
237 cache_data = (const char *) &cache->libs[cache->nlibs];
238
239 /* Check for a new cache embedded in the old format. */
a04549c1
JM
240 if (cache_size
241 > (offset + sizeof (struct cache_file_new)))
45eca4d1 242 {
e25054c4
AJ
243
244 cache_new = (struct cache_file_new *) ((void *)cache + offset);
591e1ffb 245
a986484f
UD
246 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
247 sizeof CACHEMAGIC_NEW - 1) == 0
248 && memcmp (cache_new->version, CACHE_VERSION,
249 sizeof CACHE_VERSION - 1) == 0)
e25054c4 250 {
84ba719b 251 check_new_cache (cache_new);
e25054c4
AJ
252 cache_data = (const char *) cache_new;
253 format = 1;
254 }
45eca4d1
UD
255 }
256 }
25ee87d6 257
45eca4d1
UD
258 if (format == 0)
259 {
260 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
591e1ffb 261
45eca4d1 262 /* Print everything. */
27d9ffda 263 for (unsigned int i = 0; i < cache->nlibs; i++)
45eca4d1 264 print_entry (cache_data + cache->libs[i].key,
a986484f 265 cache->libs[i].flags, 0, 0,
45eca4d1
UD
266 cache_data + cache->libs[i].value);
267 }
268 else if (format == 1)
269 {
dfb3f101
FW
270 struct cache_extension_all_loaded ext;
271 if (!cache_extension_load (cache_new, cache, cache_size, &ext))
272 error (EXIT_FAILURE, 0,
273 _("Malformed extension data in cache file %s\n"), cache_name);
274
a986484f
UD
275 printf (_("%d libs found in cache `%s'\n"),
276 cache_new->nlibs, cache_name);
45eca4d1
UD
277
278 /* Print everything. */
27d9ffda 279 for (unsigned int i = 0; i < cache_new->nlibs; i++)
45eca4d1
UD
280 print_entry (cache_data + cache_new->libs[i].key,
281 cache_new->libs[i].flags,
a986484f 282 cache_new->libs[i].osversion,
45eca4d1
UD
283 cache_new->libs[i].hwcap,
284 cache_data + cache_new->libs[i].value);
dfb3f101 285 print_extensions (&ext);
45eca4d1 286 }
591e1ffb
UD
287 /* Cleanup. */
288 munmap (cache, cache_size);
289 close (fd);
290}
291
292/* Initialize cache data structures. */
293void
294init_cache (void)
295{
296 entries = NULL;
297}
298
27d9ffda
UD
299static int
300compare (const struct cache_entry *e1, const struct cache_entry *e2)
591e1ffb 301{
591e1ffb 302 /* We need to swap entries here to get the correct sort order. */
27d9ffda 303 int res = _dl_cache_libcmp (e2->lib, e1->lib);
591e1ffb
UD
304 if (res == 0)
305 {
306 if (e1->flags < e2->flags)
307 return 1;
308 else if (e1->flags > e2->flags)
309 return -1;
45eca4d1
UD
310 /* Sort by most specific hwcap. */
311 else if (e2->bits_hwcap > e1->bits_hwcap)
312 return 1;
313 else if (e2->bits_hwcap < e1->bits_hwcap)
314 return -1;
315 else if (e2->hwcap > e1->hwcap)
316 return 1;
317 else if (e2->hwcap < e1->hwcap)
318 return -1;
a986484f
UD
319 if (e2->osversion > e1->osversion)
320 return 1;
321 if (e2->osversion < e1->osversion)
322 return -1;
591e1ffb
UD
323 }
324 return res;
325}
326
dfb3f101
FW
327/* Size of the cache extension directory. All tags are assumed to be
328 present. */
329enum
330 {
331 cache_extension_size = (offsetof (struct cache_extension, sections)
332 + (cache_extension_count
333 * sizeof (struct cache_extension_section)))
334 };
335
336/* Write the cache extensions to FD. The extension directory is
337 assumed to be located at CACHE_EXTENSION_OFFSET. */
338static void
339write_extensions (int fd, uint32_t cache_extension_offset)
340{
341 assert ((cache_extension_offset % 4) == 0);
342
343 struct cache_extension *ext = xmalloc (cache_extension_size);
344 ext->magic = cache_extension_magic;
345 ext->count = cache_extension_count;
346
347 for (int i = 0; i < cache_extension_count; ++i)
348 {
349 ext->sections[i].tag = i;
350 ext->sections[i].flags = 0;
351 }
352
353 const char *generator
354 = "ldconfig " PKGVERSION RELEASE " release version " VERSION;
355 ext->sections[cache_extension_tag_generator].offset
356 = cache_extension_offset + cache_extension_size;
357 ext->sections[cache_extension_tag_generator].size = strlen (generator);
358
359 if (write (fd, ext, cache_extension_size) != cache_extension_size
360 || write (fd, generator, strlen (generator)) != strlen (generator))
361 error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
362
363 free (ext);
364}
365
591e1ffb
UD
366/* Save the contents of the cache. */
367void
368save_cache (const char *cache_name)
369{
591e1ffb
UD
370 /* The cache entries are sorted already, save them in this order. */
371
372 /* Count the length of all strings. */
45eca4d1
UD
373 /* The old format doesn't contain hwcap entries and doesn't contain
374 libraries in subdirectories with hwcaps entries. Count therefore
375 also all entries with hwcap == 0. */
27d9ffda
UD
376 size_t total_strlen = 0;
377 struct cache_entry *entry;
378 /* Number of cache entries. */
379 int cache_entry_count = 0;
380 /* Number of normal cache entries. */
381 int cache_entry_old_count = 0;
382
591e1ffb
UD
383 for (entry = entries; entry != NULL; entry = entry->next)
384 {
385 /* Account the final NULs. */
386 total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
387 ++cache_entry_count;
45eca4d1
UD
388 if (entry->hwcap == 0)
389 ++cache_entry_old_count;
591e1ffb 390 }
25ee87d6 391
591e1ffb 392 /* Create the on disk cache structure. */
27d9ffda
UD
393 struct cache_file *file_entries = NULL;
394 size_t file_entries_size = 0;
591e1ffb 395
db07fae8 396 if (opt_format != opt_format_new)
45eca4d1 397 {
062df960
UD
398 /* struct cache_file_new is 64-bit aligned on some arches while
399 only 32-bit aligned on other arches. Duplicate last old
400 cache entry so that new cache in ld.so.cache can be used by
401 both. */
db07fae8 402 if (opt_format != opt_format_old)
062df960
UD
403 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
404
45eca4d1
UD
405 /* And the list of all entries in the old format. */
406 file_entries_size = sizeof (struct cache_file)
407 + cache_entry_old_count * sizeof (struct file_entry);
27d9ffda 408 file_entries = xmalloc (file_entries_size);
45eca4d1
UD
409
410 /* Fill in the header. */
27d9ffda 411 memset (file_entries, '\0', sizeof (struct cache_file));
45eca4d1 412 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
591e1ffb 413
45eca4d1
UD
414 file_entries->nlibs = cache_entry_old_count;
415 }
25ee87d6 416
27d9ffda
UD
417 struct cache_file_new *file_entries_new = NULL;
418 size_t file_entries_new_size = 0;
419
db07fae8 420 if (opt_format != opt_format_old)
45eca4d1
UD
421 {
422 /* And the list of all entries in the new format. */
423 file_entries_new_size = sizeof (struct cache_file_new)
424 + cache_entry_count * sizeof (struct file_entry_new);
27d9ffda 425 file_entries_new = xmalloc (file_entries_new_size);
45eca4d1
UD
426
427 /* Fill in the header. */
27d9ffda 428 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
a986484f
UD
429 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
430 sizeof CACHEMAGIC_NEW - 1);
431 memcpy (file_entries_new->version, CACHE_VERSION,
432 sizeof CACHE_VERSION - 1);
45eca4d1
UD
433
434 file_entries_new->nlibs = cache_entry_count;
435 file_entries_new->len_strings = total_strlen;
84ba719b 436 file_entries_new->flags = cache_file_new_flags_endian_current;
45eca4d1 437 }
95582174 438
27d9ffda
UD
439 /* Pad for alignment of cache_file_new. */
440 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
95582174 441
45eca4d1
UD
442 /* If we have both formats, we hide the new format in the strings
443 table, we have to adjust all string indices for this so that
444 old libc5/glibc 2 dynamic linkers just ignore them. */
27d9ffda 445 unsigned int str_offset;
db07fae8 446 if (opt_format != opt_format_old)
45eca4d1
UD
447 str_offset = file_entries_new_size;
448 else
449 str_offset = 0;
591e1ffb 450
27d9ffda
UD
451 /* An array for all strings. */
452 char *strings = xmalloc (total_strlen);
453 char *str = strings;
454 int idx_old;
455 int idx_new;
456
45eca4d1
UD
457 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
458 entry = entry->next, ++idx_new)
591e1ffb 459 {
591e1ffb 460 /* First the library. */
db07fae8 461 if (opt_format != opt_format_new && entry->hwcap == 0)
45eca4d1
UD
462 {
463 file_entries->libs[idx_old].flags = entry->flags;
464 /* XXX: Actually we can optimize here and remove duplicates. */
e25054c4 465 file_entries->libs[idx_old].key = str_offset + pad;
45eca4d1 466 }
db07fae8 467 if (opt_format != opt_format_old)
45eca4d1
UD
468 {
469 /* We could subtract file_entries_new_size from str_offset -
470 not doing so makes the code easier, the string table
ded5b9b7 471 always begins at the beginning of the new cache
45eca4d1
UD
472 struct. */
473 file_entries_new->libs[idx_new].flags = entry->flags;
a986484f 474 file_entries_new->libs[idx_new].osversion = entry->osversion;
45eca4d1
UD
475 file_entries_new->libs[idx_new].hwcap = entry->hwcap;
476 file_entries_new->libs[idx_new].key = str_offset;
477 }
27d9ffda
UD
478
479 size_t len = strlen (entry->lib) + 1;
480 str = mempcpy (str, entry->lib, len);
481 str_offset += len;
591e1ffb 482 /* Then the path. */
db07fae8 483 if (opt_format != opt_format_new && entry->hwcap == 0)
e25054c4 484 file_entries->libs[idx_old].value = str_offset + pad;
db07fae8 485 if (opt_format != opt_format_old)
45eca4d1 486 file_entries_new->libs[idx_new].value = str_offset;
27d9ffda
UD
487 len = strlen (entry->path) + 1;
488 str = mempcpy (str, entry->path, len);
489 str_offset += len;
45eca4d1
UD
490 /* Ignore entries with hwcap for old format. */
491 if (entry->hwcap == 0)
492 ++idx_old;
591e1ffb 493 }
591e1ffb 494
062df960 495 /* Duplicate last old cache entry if needed. */
db07fae8 496 if (opt_format != opt_format_new
062df960
UD
497 && idx_old < cache_entry_old_count)
498 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
499
dfb3f101
FW
500 /* Compute the location of the extension directory. This
501 implementation puts the directory after the string table. The
502 size computation matches the write calls below. The extension
503 directory does not exist with format 0, so the value does not
504 matter. */
505 uint32_t extension_offset = 0;
506 if (opt_format != opt_format_new)
507 extension_offset += file_entries_size;
508 if (opt_format != opt_format_old)
509 {
510 if (opt_format != opt_format_new)
511 extension_offset += pad;
512 extension_offset += file_entries_new_size;
513 }
514 extension_offset += total_strlen;
515 extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
516 if (opt_format != opt_format_old)
517 file_entries_new->extension_offset = extension_offset;
518
591e1ffb
UD
519 /* Write out the cache. */
520
521 /* Write cache first to a temporary file and rename it later. */
27d9ffda 522 char *temp_name = xmalloc (strlen (cache_name) + 2);
591e1ffb 523 sprintf (temp_name, "%s~", cache_name);
591e1ffb
UD
524
525 /* Create file. */
27d9ffda
UD
526 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
527 S_IRUSR|S_IWUSR);
591e1ffb
UD
528 if (fd < 0)
529 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
530 temp_name);
531
532 /* Write contents. */
db07fae8 533 if (opt_format != opt_format_new)
45eca4d1 534 {
a986484f 535 if (write (fd, file_entries, file_entries_size)
0292b0dd 536 != (ssize_t) file_entries_size)
45eca4d1
UD
537 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
538 }
db07fae8 539 if (opt_format != opt_format_old)
45eca4d1 540 {
e25054c4 541 /* Align cache. */
db07fae8 542 if (opt_format != opt_format_new)
e25054c4 543 {
a986484f 544 char zero[pad];
0292b0dd
UD
545 memset (zero, '\0', pad);
546 if (write (fd, zero, pad) != (ssize_t) pad)
e25054c4
AJ
547 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
548 }
45eca4d1 549 if (write (fd, file_entries_new, file_entries_new_size)
0292b0dd 550 != (ssize_t) file_entries_new_size)
45eca4d1
UD
551 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
552 }
591e1ffb 553
999a6dab 554 if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
11bf311e 555 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
591e1ffb 556
dfb3f101
FW
557 if (opt_format != opt_format_old)
558 {
559 /* Align file position to 4. */
560 off64_t old_offset = lseek64 (fd, extension_offset, SEEK_SET);
561 assert ((unsigned long long int) (extension_offset - old_offset) < 4);
562 write_extensions (fd, extension_offset);
563 }
564
25ee87d6 565 /* Make sure user can always read cache file */
ba9fcb3f 566 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
25ee87d6 567 error (EXIT_FAILURE, errno,
ba9fcb3f
UD
568 _("Changing access rights of %s to %#o failed"), temp_name,
569 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
25ee87d6 570
999a6dab
FW
571 /* Make sure that data is written to disk. */
572 if (fsync (fd) != 0 || close (fd) != 0)
573 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
574
591e1ffb
UD
575 /* Move temporary to its final location. */
576 if (rename (temp_name, cache_name))
577 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
578 cache_name);
25ee87d6 579
591e1ffb 580 /* Free all allocated memory. */
0292b0dd 581 free (file_entries_new);
591e1ffb
UD
582 free (file_entries);
583 free (strings);
584
585 while (entries)
586 {
587 entry = entries;
591e1ffb
UD
588 entries = entries->next;
589 free (entry);
590 }
591}
592
45eca4d1 593
591e1ffb
UD
594/* Add one library to the cache. */
595void
45eca4d1 596add_to_cache (const char *path, const char *lib, int flags,
a986484f 597 unsigned int osversion, uint64_t hwcap)
591e1ffb 598{
27d9ffda
UD
599 size_t liblen = strlen (lib) + 1;
600 size_t len = liblen + strlen (path) + 1;
601 struct cache_entry *new_entry
602 = xmalloc (sizeof (struct cache_entry) + liblen + len);
603
604 new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
605 new_entry->path = new_entry->lib + liblen;
606 snprintf (new_entry->path, len, "%s/%s", path, lib);
591e1ffb 607 new_entry->flags = flags;
a986484f 608 new_entry->osversion = osversion;
45eca4d1
UD
609 new_entry->hwcap = hwcap;
610 new_entry->bits_hwcap = 0;
611
612 /* Count the number of bits set in the masked value. */
27d9ffda
UD
613 for (size_t i = 0;
614 (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
ad1a5cc7 615 if ((hwcap & (1ULL << i)) != 0)
45eca4d1
UD
616 ++new_entry->bits_hwcap;
617
591e1ffb
UD
618
619 /* Keep the list sorted - search for right place to insert. */
27d9ffda
UD
620 struct cache_entry *ptr = entries;
621 struct cache_entry *prev = entries;
591e1ffb
UD
622 while (ptr != NULL)
623 {
624 if (compare (ptr, new_entry) > 0)
625 break;
626 prev = ptr;
627 ptr = ptr->next;
628 }
629 /* Is this the first entry? */
630 if (ptr == entries)
631 {
632 new_entry->next = entries;
633 entries = new_entry;
634 }
635 else
636 {
637 new_entry->next = prev->next;
638 prev->next = new_entry;
639 }
640}
27d9ffda
UD
641
642
643/* Auxiliary cache. */
644
645struct aux_cache_entry_id
646{
647 uint64_t ino;
648 uint64_t ctime;
649 uint64_t size;
650 uint64_t dev;
651};
652
653struct aux_cache_entry
654{
655 struct aux_cache_entry_id id;
656 int flags;
657 unsigned int osversion;
658 int used;
659 char *soname;
660 struct aux_cache_entry *next;
661};
662
663#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
664
665struct aux_cache_file_entry
666{
667 struct aux_cache_entry_id id; /* Unique id of entry. */
668 int32_t flags; /* This is 1 for an ELF library. */
669 uint32_t soname; /* String table indice. */
670 uint32_t osversion; /* Required OS version. */
671 int32_t pad;
672};
673
674/* ldconfig maintains an auxiliary cache file that allows
675 only reading those libraries that have changed since the last iteration.
676 For this for each library some information is cached in the auxiliary
677 cache. */
678struct aux_cache_file
679{
680 char magic[sizeof AUX_CACHEMAGIC - 1];
681 uint32_t nlibs; /* Number of entries. */
682 uint32_t len_strings; /* Size of string table. */
683 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
684 /* After this the string table of size len_strings is found. */
685};
686
3c87d79d 687static const unsigned int primes[] =
27d9ffda
UD
688{
689 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
690 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
691 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
692};
693
694static size_t aux_hash_size;
695static struct aux_cache_entry **aux_hash;
696
697/* Simplistic hash function for aux_cache_entry_id. */
698static unsigned int
699aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
700{
701 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
702 return ret ^ (ret >> 32);
703}
704
705static size_t nextprime (size_t x)
706{
707 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
708 if (primes[i] >= x)
709 return primes[i];
710 return x;
711}
712
713void
714init_aux_cache (void)
715{
716 aux_hash_size = primes[3];
717 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
718}
719
720int
721search_aux_cache (struct stat64 *stat_buf, int *flags,
722 unsigned int *osversion, char **soname)
723{
724 struct aux_cache_entry_id id;
725 id.ino = (uint64_t) stat_buf->st_ino;
726 id.ctime = (uint64_t) stat_buf->st_ctime;
727 id.size = (uint64_t) stat_buf->st_size;
728 id.dev = (uint64_t) stat_buf->st_dev;
729
730 unsigned int hash = aux_cache_entry_id_hash (&id);
731 struct aux_cache_entry *entry;
732 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
733 if (id.ino == entry->id.ino
734 && id.ctime == entry->id.ctime
735 && id.size == entry->id.size
736 && id.dev == entry->id.dev)
737 {
738 *flags = entry->flags;
739 *osversion = entry->osversion;
740 if (entry->soname != NULL)
741 *soname = xstrdup (entry->soname);
742 else
743 *soname = NULL;
744 entry->used = 1;
745 return 1;
746 }
747
748 return 0;
749}
750
751static void
752insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
753 unsigned int osversion, const char *soname, int used)
754{
755 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
756 struct aux_cache_entry *entry;
757 for (entry = aux_hash[hash]; entry; entry = entry->next)
758 if (id->ino == entry->id.ino
759 && id->ctime == entry->id.ctime
760 && id->size == entry->id.size
761 && id->dev == entry->id.dev)
762 abort ();
763
764 size_t len = soname ? strlen (soname) + 1 : 0;
765 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
766 entry->id = *id;
767 entry->flags = flags;
768 entry->osversion = osversion;
769 entry->used = used;
770 if (soname != NULL)
771 entry->soname = memcpy ((char *) (entry + 1), soname, len);
772 else
773 entry->soname = NULL;
774 entry->next = aux_hash[hash];
775 aux_hash[hash] = entry;
776}
777
778void
779add_to_aux_cache (struct stat64 *stat_buf, int flags,
780 unsigned int osversion, const char *soname)
781{
782 struct aux_cache_entry_id id;
783 id.ino = (uint64_t) stat_buf->st_ino;
784 id.ctime = (uint64_t) stat_buf->st_ctime;
785 id.size = (uint64_t) stat_buf->st_size;
786 id.dev = (uint64_t) stat_buf->st_dev;
787 insert_to_aux_cache (&id, flags, osversion, soname, 1);
788}
789
790/* Load auxiliary cache to search for unchanged entries. */
791void
792load_aux_cache (const char *aux_cache_name)
793{
794 int fd = open (aux_cache_name, O_RDONLY);
795 if (fd < 0)
796 {
797 init_aux_cache ();
798 return;
799 }
800
801 struct stat64 st;
04986243 802 if (__fstat64 (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
27d9ffda
UD
803 {
804 close (fd);
805 init_aux_cache ();
806 return;
807 }
808
809 size_t aux_cache_size = st.st_size;
810 struct aux_cache_file *aux_cache
811 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
812 if (aux_cache == MAP_FAILED
813 || aux_cache_size < sizeof (struct aux_cache_file)
814 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
c4f50205
JM
815 || aux_cache_size != (sizeof (struct aux_cache_file)
816 + aux_cache->nlibs * sizeof (struct aux_cache_file_entry)
34a5a146 817 + aux_cache->len_strings))
27d9ffda
UD
818 {
819 close (fd);
820 init_aux_cache ();
821 return;
822 }
823
824 aux_hash_size = nextprime (aux_cache->nlibs);
825 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
826
827 const char *aux_cache_data
828 = (const char *) &aux_cache->libs[aux_cache->nlibs];
829 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
830 insert_to_aux_cache (&aux_cache->libs[i].id,
831 aux_cache->libs[i].flags,
832 aux_cache->libs[i].osversion,
833 aux_cache->libs[i].soname == 0
834 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
835 0);
836
837 munmap (aux_cache, aux_cache_size);
838 close (fd);
839}
840
841/* Save the contents of the auxiliary cache. */
842void
843save_aux_cache (const char *aux_cache_name)
844{
845 /* Count the length of all sonames. We start with empty string. */
846 size_t total_strlen = 1;
847 /* Number of cache entries. */
848 int cache_entry_count = 0;
849
850 for (size_t i = 0; i < aux_hash_size; ++i)
851 for (struct aux_cache_entry *entry = aux_hash[i];
852 entry != NULL; entry = entry->next)
853 if (entry->used)
854 {
855 ++cache_entry_count;
856 if (entry->soname != NULL)
857 total_strlen += strlen (entry->soname) + 1;
858 }
859
860 /* Auxiliary cache. */
861 size_t file_entries_size
862 = sizeof (struct aux_cache_file)
863 + cache_entry_count * sizeof (struct aux_cache_file_entry);
864 struct aux_cache_file *file_entries
865 = xmalloc (file_entries_size + total_strlen);
866
867 /* Fill in the header of the auxiliary cache. */
868 memset (file_entries, '\0', sizeof (struct aux_cache_file));
869 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
870
871 file_entries->nlibs = cache_entry_count;
872 file_entries->len_strings = total_strlen;
873
874 /* Initial String offset for auxiliary cache is always after the
875 special empty string. */
876 unsigned int str_offset = 1;
877
878 /* An array for all strings. */
879 char *str = (char *) file_entries + file_entries_size;
880 *str++ = '\0';
881
882 size_t idx = 0;
883 for (size_t i = 0; i < aux_hash_size; ++i)
884 for (struct aux_cache_entry *entry = aux_hash[i];
885 entry != NULL; entry = entry->next)
886 if (entry->used)
887 {
888 file_entries->libs[idx].id = entry->id;
889 file_entries->libs[idx].flags = entry->flags;
890 if (entry->soname == NULL)
891 file_entries->libs[idx].soname = 0;
892 else
893 {
894 file_entries->libs[idx].soname = str_offset;
895
896 size_t len = strlen (entry->soname) + 1;
897 str = mempcpy (str, entry->soname, len);
898 str_offset += len;
899 }
900 file_entries->libs[idx].osversion = entry->osversion;
901 file_entries->libs[idx++].pad = 0;
902 }
903
904 /* Write out auxiliary cache file. */
905 /* Write auxiliary cache first to a temporary file and rename it later. */
906
907 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
908 sprintf (temp_name, "%s~", aux_cache_name);
909
910 /* Check that directory exists and create if needed. */
911 char *dir = strdupa (aux_cache_name);
912 dir = dirname (dir);
913
914 struct stat64 st;
915 if (stat64 (dir, &st) < 0)
916 {
917 if (mkdir (dir, 0700) < 0)
918 goto out_fail;
919 }
920
921 /* Create file. */
922 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
923 S_IRUSR|S_IWUSR);
924 if (fd < 0)
925 goto out_fail;
926
927 if (write (fd, file_entries, file_entries_size + total_strlen)
928 != (ssize_t) (file_entries_size + total_strlen)
999a6dab
FW
929 || fdatasync (fd) != 0
930 || close (fd) != 0)
27d9ffda
UD
931 {
932 unlink (temp_name);
933 goto out_fail;
934 }
935
936 /* Move temporary to its final location. */
937 if (rename (temp_name, aux_cache_name))
938 unlink (temp_name);
939
940out_fail:
941 /* Free allocated memory. */
78d6dd72 942 free (temp_name);
27d9ffda
UD
943 free (file_entries);
944}