]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/cache.c
elf: Add -z lazy to some more tests
[thirdparty/glibc.git] / elf / cache.c
CommitLineData
6d7e8eda 1/* Copyright (C) 1999-2023 Free Software Foundation, Inc.
591e1ffb 2 This file is part of the GNU C Library.
591e1ffb 3
43bc8ac6 4 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; version 2 of the License, or
7 (at your option) any later version.
591e1ffb 8
43bc8ac6 9 This program is distributed in the hope that it will be useful,
591e1ffb 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
591e1ffb 13
43bc8ac6 14 You should have received a copy of the GNU General Public License
5a82c748 15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
591e1ffb 16
dfb3f101 17#include <assert.h>
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>
880433de 31#include <sys/param.h>
591e1ffb
UD
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>
73b6e50a
FW
38#include <stringtable.h>
39
40/* Used to store library names, paths, and other strings. */
41static struct stringtable strings;
591e1ffb 42
b44ac4f4
FW
43/* Keeping track of "glibc-hwcaps" subdirectories. During cache
44 construction, a linear search by name is performed to deduplicate
45 entries. */
46struct glibc_hwcaps_subdirectory
47{
48 struct glibc_hwcaps_subdirectory *next;
49
50 /* Interned string with the subdirectory name. */
51 struct stringtable_entry *name;
52
53 /* Array index in the cache_extension_tag_glibc_hwcaps section in
54 the stored cached file. This is computed after all the
55 subdirectories have been processed, so that subdirectory names in
56 the extension section can be sorted. */
57 uint32_t section_index;
58
59 /* True if the subdirectory is actually used for anything. */
60 bool used;
61};
62
63const char *
64glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir)
65{
66 return dir->name->string;
67}
68
69/* Linked list of known hwcaps subdirecty names. */
70static struct glibc_hwcaps_subdirectory *hwcaps;
71
72struct glibc_hwcaps_subdirectory *
73new_glibc_hwcaps_subdirectory (const char *name)
74{
75 struct stringtable_entry *name_interned = stringtable_add (&strings, name);
76 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
77 if (p->name == name_interned)
78 return p;
79 struct glibc_hwcaps_subdirectory *p = xmalloc (sizeof (*p));
80 p->next = hwcaps;
81 p->name = name_interned;
82 p->section_index = 0;
83 p->used = false;
84 hwcaps = p;
85 return p;
86}
87
88/* Helper for sorting struct glibc_hwcaps_subdirectory elements by
89 name. */
90static int
91assign_glibc_hwcaps_indices_compare (const void *l, const void *r)
92{
93 const struct glibc_hwcaps_subdirectory *left
94 = *(struct glibc_hwcaps_subdirectory **)l;
95 const struct glibc_hwcaps_subdirectory *right
96 = *(struct glibc_hwcaps_subdirectory **)r;
97 return strcmp (glibc_hwcaps_subdirectory_name (left),
98 glibc_hwcaps_subdirectory_name (right));
99}
100
101/* Count the number of hwcaps subdirectories which are actually
102 used. */
103static size_t
104glibc_hwcaps_count (void)
105{
106 size_t count = 0;
107 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
108 if (p->used)
109 ++count;
110 return count;
111}
112
113/* Compute the section_index fields for all */
114static void
115assign_glibc_hwcaps_indices (void)
116{
117 /* Convert the linked list into an array, so that we can use qsort.
118 Only copy the subdirectories which are actually used. */
119 size_t count = glibc_hwcaps_count ();
120 struct glibc_hwcaps_subdirectory **array
121 = xmalloc (sizeof (*array) * count);
122 {
123 size_t i = 0;
124 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
125 if (p->used)
126 {
127 array[i] = p;
128 ++i;
129 }
130 assert (i == count);
131 }
132
133 qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare);
134
135 /* Assign the array indices. */
136 for (size_t i = 0; i < count; ++i)
137 array[i]->section_index = i;
138
139 free (array);
140}
141
591e1ffb
UD
142struct cache_entry
143{
73b6e50a
FW
144 struct stringtable_entry *lib; /* Library name. */
145 struct stringtable_entry *path; /* Path to find library. */
45eca4d1 146 int flags; /* Flags to indicate kind of library. */
efbbd9c3 147 unsigned int isa_level; /* Required ISA level. */
b44ac4f4 148
cfbf883d 149 /* glibc-hwcaps subdirectory. */
b44ac4f4
FW
150 struct glibc_hwcaps_subdirectory *hwcaps;
151
45eca4d1 152 struct cache_entry *next; /* Next entry in list. */
591e1ffb
UD
153};
154
591e1ffb
UD
155/* List of all cache entries. */
156static struct cache_entry *entries;
157
8ee87859 158/* libc4, ELF and libc5 are unsupported. */
591e1ffb
UD
159static const char *flag_descr[] =
160{ "libc4", "ELF", "libc5", "libc6"};
161
591e1ffb
UD
162/* Print a single entry. */
163static void
c628c229
AZ
164print_entry (const char *lib, int flag, uint64_t hwcap,
165 const char *hwcap_string, const char *key)
591e1ffb
UD
166{
167 printf ("\t%s (", lib);
0b7219cc 168 switch (flag & FLAG_TYPE_MASK)
591e1ffb 169 {
591e1ffb 170 case FLAG_ELF_LIBC6:
a986484f 171 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
591e1ffb
UD
172 break;
173 default:
8ee87859 174 fputs (_("unknown or unsupported flag"), stdout);
591e1ffb
UD
175 break;
176 }
177 switch (flag & FLAG_REQUIRED_MASK)
178 {
591e1ffb
UD
179 case FLAG_SPARC_LIB64:
180 fputs (",64bit", stdout);
48c53070 181 break;
95582174
UD
182 case FLAG_IA64_LIB64:
183 fputs (",IA-64", stdout);
fdedb42e 184 break;
fdedb42e
AJ
185 case FLAG_X8664_LIB64:
186 fputs (",x86-64", stdout);
187 break;
96c0d65d 188 case FLAG_S390_LIB64:
27d9ffda 189 fputs (",64bit", stdout);
48c53070
RM
190 break;
191 case FLAG_POWERPC_LIB64:
27d9ffda 192 fputs (",64bit", stdout);
48c53070 193 break;
b5bac573 194 case FLAG_MIPS64_LIBN32:
27d9ffda 195 fputs (",N32", stdout);
b5bac573
AO
196 break;
197 case FLAG_MIPS64_LIBN64:
27d9ffda 198 fputs (",64bit", stdout);
f1a77b01
L
199 break;
200 case FLAG_X8664_LIBX32:
201 fputs (",x32", stdout);
202 break;
6665d4a2
SM
203 case FLAG_ARM_LIBHF:
204 fputs (",hard-float", stdout);
205 break;
1f51ee92
SM
206 case FLAG_AARCH64_LIB64:
207 fputs (",AArch64", stdout);
208 break;
b39949d2
CD
209 /* Uses the ARM soft-float ABI. */
210 case FLAG_ARM_LIBSF:
211 fputs (",soft-float", stdout);
212 break;
9c21573c
MR
213 case FLAG_MIPS_LIB32_NAN2008:
214 fputs (",nan2008", stdout);
215 break;
216 case FLAG_MIPS64_LIBN32_NAN2008:
217 fputs (",N32,nan2008", stdout);
218 break;
219 case FLAG_MIPS64_LIBN64_NAN2008:
220 fputs (",64bit,nan2008", stdout);
221 break;
fb58aac5
PD
222 case FLAG_RISCV_FLOAT_ABI_SOFT:
223 fputs (",soft-float", stdout);
224 break;
225 case FLAG_RISCV_FLOAT_ABI_DOUBLE:
226 fputs (",double-float", stdout);
227 break;
591e1ffb
UD
228 case 0:
229 break;
230 default:
45eca4d1 231 printf (",%d", flag & FLAG_REQUIRED_MASK);
591e1ffb
UD
232 break;
233 }
b44ac4f4
FW
234 if (hwcap_string != NULL)
235 printf (", hwcap: \"%s\"", hwcap_string);
236 else if (hwcap != 0)
ab1d521d 237 printf (", hwcap: %#.16" PRIx64, hwcap);
591e1ffb
UD
238 printf (") => %s\n", key);
239}
240
b44ac4f4
FW
241/* Returns the string with the name of the glibcs-hwcaps subdirectory
242 associated with ENTRY->hwcap. file_base must be the base address
243 for string table indices. */
244static const char *
245glibc_hwcaps_string (struct cache_extension_all_loaded *ext,
246 const void *file_base, size_t file_size,
247 struct file_entry_new *entry)
248{
249 const uint32_t *hwcaps_array
250 = ext->sections[cache_extension_tag_glibc_hwcaps].base;
251 if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL)
252 {
253 uint32_t index = (uint32_t) entry->hwcap;
254 if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4)
255 {
256 uint32_t string_table_index = hwcaps_array[index];
257 if (string_table_index < file_size)
258 return file_base + string_table_index;
259 }
260 }
261 return NULL;
262}
263
84ba719b
FW
264/* Print an error and exit if the new-file cache is internally
265 inconsistent. */
266static void
267check_new_cache (struct cache_file_new *cache)
268{
269 if (! cache_file_new_matches_endian (cache))
270 error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
271}
591e1ffb 272
b44ac4f4 273/* Print the extension information in *EXT. */
dfb3f101
FW
274static void
275print_extensions (struct cache_extension_all_loaded *ext)
276{
277 if (ext->sections[cache_extension_tag_generator].base != NULL)
278 {
279 fputs (_("Cache generated by: "), stdout);
280 fwrite (ext->sections[cache_extension_tag_generator].base, 1,
281 ext->sections[cache_extension_tag_generator].size, stdout);
282 putchar ('\n');
283 }
284}
285
45eca4d1
UD
286/* Print the whole cache file, if a file contains the new cache format
287 hidden in the old one, print the contents of the new format. */
591e1ffb
UD
288void
289print_cache (const char *cache_name)
290{
27d9ffda 291 int fd = open (cache_name, O_RDONLY);
591e1ffb
UD
292 if (fd < 0)
293 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
294
9fe6f636
AZ
295 struct stat st;
296 if (fstat (fd, &st) < 0
591e1ffb
UD
297 /* No need to map the file if it is empty. */
298 || st.st_size == 0)
299 {
300 close (fd);
301 return;
302 }
25ee87d6 303
27d9ffda
UD
304 struct cache_file *cache
305 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
591e1ffb
UD
306 if (cache == MAP_FAILED)
307 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
591e1ffb 308
27d9ffda 309 size_t cache_size = st.st_size;
45eca4d1
UD
310 if (cache_size < sizeof (struct cache_file))
311 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
312
27d9ffda
UD
313 struct cache_file_new *cache_new = NULL;
314 const char *cache_data;
315 int format = 0;
316
45eca4d1
UD
317 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
318 {
319 /* This can only be the new format without the old one. */
320 cache_new = (struct cache_file_new *) cache;
321
322 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
323 || memcmp (cache_new->version, CACHE_VERSION,
324 sizeof CACHE_VERSION - 1))
325 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
84ba719b 326 check_new_cache (cache_new);
45eca4d1
UD
327 format = 1;
328 /* This is where the strings start. */
e25054c4 329 cache_data = (const char *) cache_new;
45eca4d1
UD
330 }
331 else
332 {
2954daf0
AS
333 /* Check for corruption, avoiding overflow. */
334 if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry)
335 < cache->nlibs)
336 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
337
e25054c4 338 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
a986484f
UD
339 + (cache->nlibs
340 * sizeof (struct file_entry)));
45eca4d1
UD
341 /* This is where the strings start. */
342 cache_data = (const char *) &cache->libs[cache->nlibs];
343
344 /* Check for a new cache embedded in the old format. */
a04549c1
JM
345 if (cache_size
346 > (offset + sizeof (struct cache_file_new)))
45eca4d1 347 {
e25054c4
AJ
348
349 cache_new = (struct cache_file_new *) ((void *)cache + offset);
591e1ffb 350
a986484f
UD
351 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
352 sizeof CACHEMAGIC_NEW - 1) == 0
353 && memcmp (cache_new->version, CACHE_VERSION,
354 sizeof CACHE_VERSION - 1) == 0)
e25054c4 355 {
84ba719b 356 check_new_cache (cache_new);
e25054c4
AJ
357 cache_data = (const char *) cache_new;
358 format = 1;
359 }
45eca4d1
UD
360 }
361 }
25ee87d6 362
45eca4d1
UD
363 if (format == 0)
364 {
365 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
591e1ffb 366
45eca4d1 367 /* Print everything. */
27d9ffda 368 for (unsigned int i = 0; i < cache->nlibs; i++)
45eca4d1 369 print_entry (cache_data + cache->libs[i].key,
c628c229 370 cache->libs[i].flags, 0, NULL,
45eca4d1
UD
371 cache_data + cache->libs[i].value);
372 }
373 else if (format == 1)
374 {
dfb3f101
FW
375 struct cache_extension_all_loaded ext;
376 if (!cache_extension_load (cache_new, cache, cache_size, &ext))
377 error (EXIT_FAILURE, 0,
378 _("Malformed extension data in cache file %s\n"), cache_name);
379
a986484f
UD
380 printf (_("%d libs found in cache `%s'\n"),
381 cache_new->nlibs, cache_name);
45eca4d1
UD
382
383 /* Print everything. */
27d9ffda 384 for (unsigned int i = 0; i < cache_new->nlibs; i++)
b44ac4f4
FW
385 {
386 const char *hwcaps_string
387 = glibc_hwcaps_string (&ext, cache, cache_size,
388 &cache_new->libs[i]);
389 print_entry (cache_data + cache_new->libs[i].key,
390 cache_new->libs[i].flags,
b44ac4f4
FW
391 cache_new->libs[i].hwcap, hwcaps_string,
392 cache_data + cache_new->libs[i].value);
393 }
dfb3f101 394 print_extensions (&ext);
45eca4d1 395 }
591e1ffb
UD
396 /* Cleanup. */
397 munmap (cache, cache_size);
398 close (fd);
399}
400
401/* Initialize cache data structures. */
402void
403init_cache (void)
404{
405 entries = NULL;
406}
407
27d9ffda
UD
408static int
409compare (const struct cache_entry *e1, const struct cache_entry *e2)
591e1ffb 410{
591e1ffb 411 /* We need to swap entries here to get the correct sort order. */
73b6e50a 412 int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string);
591e1ffb
UD
413 if (res == 0)
414 {
415 if (e1->flags < e2->flags)
416 return 1;
417 else if (e1->flags > e2->flags)
418 return -1;
b44ac4f4
FW
419 /* Keep the glibc-hwcaps extension entries before the regular
420 entries, and sort them by their names. search_cache in
421 dl-cache.c stops searching once the first non-extension entry
422 is found, so the extension entries need to come first. */
423 else if (e1->hwcaps != NULL && e2->hwcaps == NULL)
424 return -1;
425 else if (e1->hwcaps == NULL && e2->hwcaps != NULL)
426 return 1;
427 else if (e1->hwcaps != NULL && e2->hwcaps != NULL)
428 {
429 res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps),
430 glibc_hwcaps_subdirectory_name (e2->hwcaps));
431 if (res != 0)
432 return res;
433 }
591e1ffb
UD
434 }
435 return res;
436}
437
dfb3f101
FW
438/* Size of the cache extension directory. All tags are assumed to be
439 present. */
440enum
441 {
442 cache_extension_size = (offsetof (struct cache_extension, sections)
443 + (cache_extension_count
444 * sizeof (struct cache_extension_section)))
445 };
446
b44ac4f4
FW
447/* Write the cache extensions to FD. The string table is shifted by
448 STRING_TABLE_OFFSET. The extension directory is assumed to be
449 located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices
450 must have been called. */
dfb3f101 451static void
b44ac4f4
FW
452write_extensions (int fd, uint32_t str_offset,
453 uint32_t cache_extension_offset)
dfb3f101
FW
454{
455 assert ((cache_extension_offset % 4) == 0);
456
b44ac4f4
FW
457 /* The length and contents of the glibc-hwcaps section. */
458 uint32_t hwcaps_count = glibc_hwcaps_count ();
459 uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size;
460 uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t);
461 uint32_t *hwcaps_array = xmalloc (hwcaps_size);
462 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
463 if (p->used)
464 hwcaps_array[p->section_index] = str_offset + p->name->offset;
465
466 /* This is the offset of the generator string. */
467 uint32_t generator_offset = hwcaps_offset;
468 if (hwcaps_count == 0)
469 /* There is no section for the hwcaps subdirectories. */
470 generator_offset -= sizeof (struct cache_extension_section);
471 else
472 /* The string table indices for the hwcaps subdirectories shift
473 the generator string backwards. */
474 generator_offset += hwcaps_size;
475
dfb3f101
FW
476 struct cache_extension *ext = xmalloc (cache_extension_size);
477 ext->magic = cache_extension_magic;
dfb3f101 478
b44ac4f4
FW
479 /* Extension index current being filled. */
480 size_t xid = 0;
dfb3f101
FW
481
482 const char *generator
483 = "ldconfig " PKGVERSION RELEASE " release version " VERSION;
b44ac4f4
FW
484 ext->sections[xid].tag = cache_extension_tag_generator;
485 ext->sections[xid].flags = 0;
486 ext->sections[xid].offset = generator_offset;
487 ext->sections[xid].size = strlen (generator);
488
489 if (hwcaps_count > 0)
490 {
491 ++xid;
492 ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps;
493 ext->sections[xid].flags = 0;
494 ext->sections[xid].offset = hwcaps_offset;
495 ext->sections[xid].size = hwcaps_size;
496 }
dfb3f101 497
b44ac4f4
FW
498 ++xid;
499 ext->count = xid;
500 assert (xid <= cache_extension_count);
501
502 size_t ext_size = (offsetof (struct cache_extension, sections)
503 + xid * sizeof (struct cache_extension_section));
504 if (write (fd, ext, ext_size) != ext_size
505 || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size
dfb3f101
FW
506 || write (fd, generator, strlen (generator)) != strlen (generator))
507 error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
508
a85cdcdb 509 free (hwcaps_array);
dfb3f101
FW
510 free (ext);
511}
512
efbbd9c3
L
513/* Compute the hwcap value from ENTRY. */
514static inline uint64_t
515compute_hwcap_value (struct cache_entry *entry)
516{
517 if (entry->isa_level > DL_CACHE_HWCAP_ISA_LEVEL_MASK)
518 error (EXIT_FAILURE, 0, _("%s: ISA level is too high (%d > %d)"),
519 entry->path->string, entry->isa_level,
520 DL_CACHE_HWCAP_ISA_LEVEL_MASK);
521 return (DL_CACHE_HWCAP_EXTENSION
522 | (((uint64_t) entry->isa_level) << 32)
523 | entry->hwcaps->section_index);
524}
525
591e1ffb
UD
526/* Save the contents of the cache. */
527void
528save_cache (const char *cache_name)
529{
591e1ffb
UD
530 /* The cache entries are sorted already, save them in this order. */
531
b44ac4f4
FW
532 assign_glibc_hwcaps_indices ();
533
27d9ffda
UD
534 struct cache_entry *entry;
535 /* Number of cache entries. */
536 int cache_entry_count = 0;
73b6e50a
FW
537 /* The old format doesn't contain hwcap entries and doesn't contain
538 libraries in subdirectories with hwcaps entries. Count therefore
cfbf883d 539 all entries. */
27d9ffda
UD
540 int cache_entry_old_count = 0;
541
591e1ffb
UD
542 for (entry = entries; entry != NULL; entry = entry->next)
543 {
591e1ffb 544 ++cache_entry_count;
cfbf883d 545 ++cache_entry_old_count;
591e1ffb 546 }
25ee87d6 547
73b6e50a
FW
548 struct stringtable_finalized strings_finalized;
549 stringtable_finalize (&strings, &strings_finalized);
550
591e1ffb 551 /* Create the on disk cache structure. */
27d9ffda
UD
552 struct cache_file *file_entries = NULL;
553 size_t file_entries_size = 0;
591e1ffb 554
db07fae8 555 if (opt_format != opt_format_new)
45eca4d1 556 {
062df960
UD
557 /* struct cache_file_new is 64-bit aligned on some arches while
558 only 32-bit aligned on other arches. Duplicate last old
559 cache entry so that new cache in ld.so.cache can be used by
560 both. */
db07fae8 561 if (opt_format != opt_format_old)
062df960
UD
562 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
563
45eca4d1
UD
564 /* And the list of all entries in the old format. */
565 file_entries_size = sizeof (struct cache_file)
566 + cache_entry_old_count * sizeof (struct file_entry);
27d9ffda 567 file_entries = xmalloc (file_entries_size);
45eca4d1
UD
568
569 /* Fill in the header. */
27d9ffda 570 memset (file_entries, '\0', sizeof (struct cache_file));
45eca4d1 571 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
591e1ffb 572
45eca4d1
UD
573 file_entries->nlibs = cache_entry_old_count;
574 }
25ee87d6 575
27d9ffda
UD
576 struct cache_file_new *file_entries_new = NULL;
577 size_t file_entries_new_size = 0;
578
db07fae8 579 if (opt_format != opt_format_old)
45eca4d1
UD
580 {
581 /* And the list of all entries in the new format. */
582 file_entries_new_size = sizeof (struct cache_file_new)
583 + cache_entry_count * sizeof (struct file_entry_new);
27d9ffda 584 file_entries_new = xmalloc (file_entries_new_size);
45eca4d1
UD
585
586 /* Fill in the header. */
27d9ffda 587 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
a986484f
UD
588 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
589 sizeof CACHEMAGIC_NEW - 1);
590 memcpy (file_entries_new->version, CACHE_VERSION,
591 sizeof CACHE_VERSION - 1);
45eca4d1
UD
592
593 file_entries_new->nlibs = cache_entry_count;
73b6e50a 594 file_entries_new->len_strings = strings_finalized.size;
84ba719b 595 file_entries_new->flags = cache_file_new_flags_endian_current;
45eca4d1 596 }
95582174 597
27d9ffda
UD
598 /* Pad for alignment of cache_file_new. */
599 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
95582174 600
45eca4d1
UD
601 /* If we have both formats, we hide the new format in the strings
602 table, we have to adjust all string indices for this so that
603 old libc5/glibc 2 dynamic linkers just ignore them. */
27d9ffda 604 unsigned int str_offset;
db07fae8 605 if (opt_format != opt_format_old)
45eca4d1
UD
606 str_offset = file_entries_new_size;
607 else
608 str_offset = 0;
591e1ffb 609
27d9ffda 610 /* An array for all strings. */
27d9ffda
UD
611 int idx_old;
612 int idx_new;
613
45eca4d1
UD
614 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
615 entry = entry->next, ++idx_new)
591e1ffb 616 {
cfbf883d 617 if (opt_format != opt_format_new)
45eca4d1
UD
618 {
619 file_entries->libs[idx_old].flags = entry->flags;
620 /* XXX: Actually we can optimize here and remove duplicates. */
e25054c4 621 file_entries->libs[idx_old].key = str_offset + pad;
73b6e50a
FW
622 file_entries->libs[idx_new].key = str_offset + entry->lib->offset;
623 file_entries->libs[idx_new].value
624 = str_offset + entry->path->offset;
45eca4d1 625 }
db07fae8 626 if (opt_format != opt_format_old)
45eca4d1
UD
627 {
628 /* We could subtract file_entries_new_size from str_offset -
629 not doing so makes the code easier, the string table
ded5b9b7 630 always begins at the beginning of the new cache
45eca4d1
UD
631 struct. */
632 file_entries_new->libs[idx_new].flags = entry->flags;
c628c229 633 file_entries_new->libs[idx_new].osversion_unused = 0;
b44ac4f4 634 if (entry->hwcaps == NULL)
cfbf883d 635 file_entries_new->libs[idx_new].hwcap = 0;
b44ac4f4
FW
636 else
637 file_entries_new->libs[idx_new].hwcap
efbbd9c3 638 = compute_hwcap_value (entry);
73b6e50a
FW
639 file_entries_new->libs[idx_new].key
640 = str_offset + entry->lib->offset;
641 file_entries_new->libs[idx_new].value
642 = str_offset + entry->path->offset;
45eca4d1 643 }
27d9ffda 644
cfbf883d 645 ++idx_old;
591e1ffb 646 }
591e1ffb 647
062df960 648 /* Duplicate last old cache entry if needed. */
db07fae8 649 if (opt_format != opt_format_new
062df960
UD
650 && idx_old < cache_entry_old_count)
651 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
652
dfb3f101
FW
653 /* Compute the location of the extension directory. This
654 implementation puts the directory after the string table. The
655 size computation matches the write calls below. The extension
656 directory does not exist with format 0, so the value does not
657 matter. */
658 uint32_t extension_offset = 0;
659 if (opt_format != opt_format_new)
660 extension_offset += file_entries_size;
661 if (opt_format != opt_format_old)
662 {
663 if (opt_format != opt_format_new)
664 extension_offset += pad;
665 extension_offset += file_entries_new_size;
666 }
73b6e50a 667 extension_offset += strings_finalized.size;
dfb3f101
FW
668 extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
669 if (opt_format != opt_format_old)
670 file_entries_new->extension_offset = extension_offset;
671
591e1ffb
UD
672 /* Write out the cache. */
673
674 /* Write cache first to a temporary file and rename it later. */
27d9ffda 675 char *temp_name = xmalloc (strlen (cache_name) + 2);
591e1ffb 676 sprintf (temp_name, "%s~", cache_name);
591e1ffb
UD
677
678 /* Create file. */
27d9ffda
UD
679 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
680 S_IRUSR|S_IWUSR);
591e1ffb
UD
681 if (fd < 0)
682 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
683 temp_name);
684
685 /* Write contents. */
db07fae8 686 if (opt_format != opt_format_new)
45eca4d1 687 {
a986484f 688 if (write (fd, file_entries, file_entries_size)
0292b0dd 689 != (ssize_t) file_entries_size)
45eca4d1
UD
690 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
691 }
db07fae8 692 if (opt_format != opt_format_old)
45eca4d1 693 {
e25054c4 694 /* Align cache. */
db07fae8 695 if (opt_format != opt_format_new)
e25054c4 696 {
a986484f 697 char zero[pad];
0292b0dd
UD
698 memset (zero, '\0', pad);
699 if (write (fd, zero, pad) != (ssize_t) pad)
e25054c4
AJ
700 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
701 }
45eca4d1 702 if (write (fd, file_entries_new, file_entries_new_size)
0292b0dd 703 != (ssize_t) file_entries_new_size)
45eca4d1
UD
704 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
705 }
591e1ffb 706
73b6e50a
FW
707 if (write (fd, strings_finalized.strings, strings_finalized.size)
708 != (ssize_t) strings_finalized.size)
11bf311e 709 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
591e1ffb 710
dfb3f101
FW
711 if (opt_format != opt_format_old)
712 {
713 /* Align file position to 4. */
5e89ed42
YY
714 __attribute__ ((unused)) off64_t old_offset
715 = lseek64 (fd, extension_offset, SEEK_SET);
dfb3f101 716 assert ((unsigned long long int) (extension_offset - old_offset) < 4);
b44ac4f4 717 write_extensions (fd, str_offset, extension_offset);
dfb3f101
FW
718 }
719
25ee87d6 720 /* Make sure user can always read cache file */
ba9fcb3f 721 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
25ee87d6 722 error (EXIT_FAILURE, errno,
ba9fcb3f
UD
723 _("Changing access rights of %s to %#o failed"), temp_name,
724 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
25ee87d6 725
999a6dab
FW
726 /* Make sure that data is written to disk. */
727 if (fsync (fd) != 0 || close (fd) != 0)
728 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
729
591e1ffb
UD
730 /* Move temporary to its final location. */
731 if (rename (temp_name, cache_name))
732 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
733 cache_name);
25ee87d6 734
591e1ffb 735 /* Free all allocated memory. */
0292b0dd 736 free (file_entries_new);
591e1ffb 737 free (file_entries);
73b6e50a 738 free (strings_finalized.strings);
a85cdcdb 739 free (temp_name);
591e1ffb
UD
740
741 while (entries)
742 {
743 entry = entries;
591e1ffb
UD
744 entries = entries->next;
745 free (entry);
746 }
747}
748
45eca4d1 749
591e1ffb
UD
750/* Add one library to the cache. */
751void
b44ac4f4 752add_to_cache (const char *path, const char *filename, const char *soname,
4a709411 753 int flags, unsigned int isa_level,
b44ac4f4 754 struct glibc_hwcaps_subdirectory *hwcaps)
591e1ffb 755{
73b6e50a
FW
756 struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
757
758 struct stringtable_entry *path_interned;
759 {
760 char *p;
b44ac4f4 761 if (asprintf (&p, "%s/%s", path, filename) < 0)
73b6e50a
FW
762 error (EXIT_FAILURE, errno, _("Could not create library path"));
763 path_interned = stringtable_add (&strings, p);
764 free (p);
765 }
766
b44ac4f4 767 new_entry->lib = stringtable_add (&strings, soname);
73b6e50a 768 new_entry->path = path_interned;
591e1ffb 769 new_entry->flags = flags;
efbbd9c3 770 new_entry->isa_level = isa_level;
b44ac4f4 771 new_entry->hwcaps = hwcaps;
45eca4d1 772
b44ac4f4 773 if (hwcaps != NULL)
4a709411 774 hwcaps->used = true;
591e1ffb
UD
775
776 /* Keep the list sorted - search for right place to insert. */
27d9ffda
UD
777 struct cache_entry *ptr = entries;
778 struct cache_entry *prev = entries;
591e1ffb
UD
779 while (ptr != NULL)
780 {
781 if (compare (ptr, new_entry) > 0)
782 break;
783 prev = ptr;
784 ptr = ptr->next;
785 }
786 /* Is this the first entry? */
787 if (ptr == entries)
788 {
789 new_entry->next = entries;
790 entries = new_entry;
791 }
792 else
793 {
794 new_entry->next = prev->next;
795 prev->next = new_entry;
796 }
797}
27d9ffda
UD
798
799
800/* Auxiliary cache. */
801
802struct aux_cache_entry_id
803{
804 uint64_t ino;
805 uint64_t ctime;
806 uint64_t size;
807 uint64_t dev;
808};
809
810struct aux_cache_entry
811{
812 struct aux_cache_entry_id id;
813 int flags;
efbbd9c3 814 unsigned int isa_level;
27d9ffda
UD
815 int used;
816 char *soname;
817 struct aux_cache_entry *next;
818};
819
820#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
821
822struct aux_cache_file_entry
823{
824 struct aux_cache_entry_id id; /* Unique id of entry. */
825 int32_t flags; /* This is 1 for an ELF library. */
826 uint32_t soname; /* String table indice. */
efbbd9c3 827 uint32_t isa_level; /* Required ISA level. */
27d9ffda
UD
828};
829
830/* ldconfig maintains an auxiliary cache file that allows
831 only reading those libraries that have changed since the last iteration.
832 For this for each library some information is cached in the auxiliary
833 cache. */
834struct aux_cache_file
835{
836 char magic[sizeof AUX_CACHEMAGIC - 1];
837 uint32_t nlibs; /* Number of entries. */
838 uint32_t len_strings; /* Size of string table. */
839 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
840 /* After this the string table of size len_strings is found. */
841};
842
3c87d79d 843static const unsigned int primes[] =
27d9ffda
UD
844{
845 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
846 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
847 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
848};
849
850static size_t aux_hash_size;
851static struct aux_cache_entry **aux_hash;
852
853/* Simplistic hash function for aux_cache_entry_id. */
854static unsigned int
855aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
856{
857 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
858 return ret ^ (ret >> 32);
859}
860
861static size_t nextprime (size_t x)
862{
863 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
864 if (primes[i] >= x)
865 return primes[i];
866 return x;
867}
868
869void
870init_aux_cache (void)
871{
872 aux_hash_size = primes[3];
873 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
874}
875
876int
c628c229 877search_aux_cache (struct stat *stat_buf, int *flags, unsigned int *isa_level,
efbbd9c3 878 char **soname)
27d9ffda
UD
879{
880 struct aux_cache_entry_id id;
881 id.ino = (uint64_t) stat_buf->st_ino;
882 id.ctime = (uint64_t) stat_buf->st_ctime;
883 id.size = (uint64_t) stat_buf->st_size;
884 id.dev = (uint64_t) stat_buf->st_dev;
885
886 unsigned int hash = aux_cache_entry_id_hash (&id);
887 struct aux_cache_entry *entry;
888 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
889 if (id.ino == entry->id.ino
890 && id.ctime == entry->id.ctime
891 && id.size == entry->id.size
892 && id.dev == entry->id.dev)
893 {
894 *flags = entry->flags;
efbbd9c3 895 *isa_level = entry->isa_level;
27d9ffda
UD
896 if (entry->soname != NULL)
897 *soname = xstrdup (entry->soname);
898 else
899 *soname = NULL;
900 entry->used = 1;
901 return 1;
902 }
903
904 return 0;
905}
906
907static void
908insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
c628c229 909 unsigned int isa_level, const char *soname, int used)
27d9ffda
UD
910{
911 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
912 struct aux_cache_entry *entry;
913 for (entry = aux_hash[hash]; entry; entry = entry->next)
914 if (id->ino == entry->id.ino
915 && id->ctime == entry->id.ctime
916 && id->size == entry->id.size
917 && id->dev == entry->id.dev)
918 abort ();
919
920 size_t len = soname ? strlen (soname) + 1 : 0;
921 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
922 entry->id = *id;
923 entry->flags = flags;
efbbd9c3 924 entry->isa_level = isa_level;
27d9ffda
UD
925 entry->used = used;
926 if (soname != NULL)
927 entry->soname = memcpy ((char *) (entry + 1), soname, len);
928 else
929 entry->soname = NULL;
930 entry->next = aux_hash[hash];
931 aux_hash[hash] = entry;
932}
933
934void
c628c229 935add_to_aux_cache (struct stat *stat_buf, int flags, unsigned int isa_level,
efbbd9c3 936 const char *soname)
27d9ffda
UD
937{
938 struct aux_cache_entry_id id;
939 id.ino = (uint64_t) stat_buf->st_ino;
940 id.ctime = (uint64_t) stat_buf->st_ctime;
941 id.size = (uint64_t) stat_buf->st_size;
942 id.dev = (uint64_t) stat_buf->st_dev;
c628c229 943 insert_to_aux_cache (&id, flags, isa_level, soname, 1);
27d9ffda
UD
944}
945
946/* Load auxiliary cache to search for unchanged entries. */
947void
948load_aux_cache (const char *aux_cache_name)
949{
950 int fd = open (aux_cache_name, O_RDONLY);
951 if (fd < 0)
952 {
953 init_aux_cache ();
954 return;
955 }
956
9fe6f636
AZ
957 struct stat st;
958 if (fstat (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
27d9ffda
UD
959 {
960 close (fd);
961 init_aux_cache ();
962 return;
963 }
964
965 size_t aux_cache_size = st.st_size;
966 struct aux_cache_file *aux_cache
967 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
968 if (aux_cache == MAP_FAILED
969 || aux_cache_size < sizeof (struct aux_cache_file)
970 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
c4f50205
JM
971 || aux_cache_size != (sizeof (struct aux_cache_file)
972 + aux_cache->nlibs * sizeof (struct aux_cache_file_entry)
34a5a146 973 + aux_cache->len_strings))
27d9ffda 974 {
a85cdcdb
SP
975 if (aux_cache != MAP_FAILED)
976 munmap (aux_cache, aux_cache_size);
977
27d9ffda
UD
978 close (fd);
979 init_aux_cache ();
980 return;
981 }
982
983 aux_hash_size = nextprime (aux_cache->nlibs);
984 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
985
986 const char *aux_cache_data
987 = (const char *) &aux_cache->libs[aux_cache->nlibs];
988 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
989 insert_to_aux_cache (&aux_cache->libs[i].id,
990 aux_cache->libs[i].flags,
efbbd9c3 991 aux_cache->libs[i].isa_level,
27d9ffda
UD
992 aux_cache->libs[i].soname == 0
993 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
994 0);
995
996 munmap (aux_cache, aux_cache_size);
997 close (fd);
998}
999
1000/* Save the contents of the auxiliary cache. */
1001void
1002save_aux_cache (const char *aux_cache_name)
1003{
1004 /* Count the length of all sonames. We start with empty string. */
1005 size_t total_strlen = 1;
1006 /* Number of cache entries. */
1007 int cache_entry_count = 0;
1008
1009 for (size_t i = 0; i < aux_hash_size; ++i)
1010 for (struct aux_cache_entry *entry = aux_hash[i];
1011 entry != NULL; entry = entry->next)
1012 if (entry->used)
1013 {
1014 ++cache_entry_count;
1015 if (entry->soname != NULL)
1016 total_strlen += strlen (entry->soname) + 1;
1017 }
1018
1019 /* Auxiliary cache. */
1020 size_t file_entries_size
1021 = sizeof (struct aux_cache_file)
1022 + cache_entry_count * sizeof (struct aux_cache_file_entry);
1023 struct aux_cache_file *file_entries
1024 = xmalloc (file_entries_size + total_strlen);
1025
1026 /* Fill in the header of the auxiliary cache. */
1027 memset (file_entries, '\0', sizeof (struct aux_cache_file));
1028 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
1029
1030 file_entries->nlibs = cache_entry_count;
1031 file_entries->len_strings = total_strlen;
1032
1033 /* Initial String offset for auxiliary cache is always after the
1034 special empty string. */
1035 unsigned int str_offset = 1;
1036
1037 /* An array for all strings. */
1038 char *str = (char *) file_entries + file_entries_size;
1039 *str++ = '\0';
1040
1041 size_t idx = 0;
1042 for (size_t i = 0; i < aux_hash_size; ++i)
1043 for (struct aux_cache_entry *entry = aux_hash[i];
1044 entry != NULL; entry = entry->next)
1045 if (entry->used)
1046 {
1047 file_entries->libs[idx].id = entry->id;
1048 file_entries->libs[idx].flags = entry->flags;
1049 if (entry->soname == NULL)
1050 file_entries->libs[idx].soname = 0;
1051 else
1052 {
1053 file_entries->libs[idx].soname = str_offset;
1054
1055 size_t len = strlen (entry->soname) + 1;
1056 str = mempcpy (str, entry->soname, len);
1057 str_offset += len;
1058 }
efbbd9c3 1059 file_entries->libs[idx++].isa_level = entry->isa_level;
27d9ffda
UD
1060 }
1061
1062 /* Write out auxiliary cache file. */
1063 /* Write auxiliary cache first to a temporary file and rename it later. */
1064
1065 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
1066 sprintf (temp_name, "%s~", aux_cache_name);
1067
1068 /* Check that directory exists and create if needed. */
1069 char *dir = strdupa (aux_cache_name);
1070 dir = dirname (dir);
1071
9fe6f636
AZ
1072 struct stat st;
1073 if (stat (dir, &st) < 0)
27d9ffda
UD
1074 {
1075 if (mkdir (dir, 0700) < 0)
1076 goto out_fail;
1077 }
1078
1079 /* Create file. */
1080 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
1081 S_IRUSR|S_IWUSR);
1082 if (fd < 0)
1083 goto out_fail;
1084
a85cdcdb
SP
1085 bool fail = ((write (fd, file_entries, file_entries_size + total_strlen)
1086 != (ssize_t) (file_entries_size + total_strlen))
1087 || fdatasync (fd) != 0);
1088
1089 fail |= close (fd) != 0;
1090
1091 if (fail)
27d9ffda
UD
1092 {
1093 unlink (temp_name);
1094 goto out_fail;
1095 }
1096
1097 /* Move temporary to its final location. */
1098 if (rename (temp_name, aux_cache_name))
1099 unlink (temp_name);
1100
1101out_fail:
1102 /* Free allocated memory. */
78d6dd72 1103 free (temp_name);
27d9ffda
UD
1104 free (file_entries);
1105}