elf: Ignore loader debug env vars for setuid
[glibc.git] / elf / cache.c
blob8149f889bab9f9cb32a50e349991ba821e4db0dd
1 /* Copyright (C) 2022-2023 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This program is free software; you can redistribute it and/or modify
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.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
17 #include <assert.h>
18 #include <errno.h>
19 #include <error.h>
20 #include <dirent.h>
21 #include <inttypes.h>
22 #include <libgen.h>
23 #include <libintl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <sys/fcntl.h>
30 #include <sys/mman.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
35 #include <ldconfig.h>
36 #include <dl-cache.h>
37 #include <version.h>
38 #include <stringtable.h>
40 /* Used to store library names, paths, and other strings. */
41 static struct stringtable strings;
43 /* Keeping track of "glibc-hwcaps" subdirectories. During cache
44 construction, a linear search by name is performed to deduplicate
45 entries. */
46 struct glibc_hwcaps_subdirectory
48 struct glibc_hwcaps_subdirectory *next;
50 /* Interned string with the subdirectory name. */
51 struct stringtable_entry *name;
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;
59 /* True if the subdirectory is actually used for anything. */
60 bool used;
63 const char *
64 glibc_hwcaps_subdirectory_name (const struct glibc_hwcaps_subdirectory *dir)
66 return dir->name->string;
69 /* Linked list of known hwcaps subdirectory names. */
70 static struct glibc_hwcaps_subdirectory *hwcaps;
72 struct glibc_hwcaps_subdirectory *
73 new_glibc_hwcaps_subdirectory (const char *name)
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;
88 /* Helper for sorting struct glibc_hwcaps_subdirectory elements by
89 name. */
90 static int
91 assign_glibc_hwcaps_indices_compare (const void *l, const void *r)
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));
101 /* Count the number of hwcaps subdirectories which are actually
102 used. */
103 static size_t
104 glibc_hwcaps_count (void)
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;
113 /* Compute the section_index fields for all */
114 static void
115 assign_glibc_hwcaps_indices (void)
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);
123 size_t i = 0;
124 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
125 if (p->used)
127 array[i] = p;
128 ++i;
130 assert (i == count);
133 qsort (array, count, sizeof (*array), assign_glibc_hwcaps_indices_compare);
135 /* Assign the array indices. */
136 for (size_t i = 0; i < count; ++i)
137 array[i]->section_index = i;
139 free (array);
142 struct cache_entry
144 struct stringtable_entry *lib; /* Library name. */
145 struct stringtable_entry *path; /* Path to find library. */
146 int flags; /* Flags to indicate kind of library. */
147 unsigned int isa_level; /* Required ISA level. */
149 /* glibc-hwcaps subdirectory. */
150 struct glibc_hwcaps_subdirectory *hwcaps;
152 struct cache_entry *next; /* Next entry in list. */
155 /* List of all cache entries. */
156 static struct cache_entry *entries;
158 /* libc4, ELF and libc5 are unsupported. */
159 static const char *flag_descr[] =
160 { "libc4", "ELF", "libc5", "libc6"};
162 /* Print a single entry. */
163 static void
164 print_entry (const char *lib, int flag, uint64_t hwcap,
165 const char *hwcap_string, const char *key)
167 printf ("\t%s (", lib);
168 switch (flag & FLAG_TYPE_MASK)
170 case FLAG_ELF_LIBC6:
171 fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
172 break;
173 default:
174 fputs (_("unknown or unsupported flag"), stdout);
175 break;
177 switch (flag & FLAG_REQUIRED_MASK)
179 case FLAG_SPARC_LIB64:
180 fputs (",64bit", stdout);
181 break;
182 case FLAG_IA64_LIB64:
183 fputs (",IA-64", stdout);
184 break;
185 case FLAG_X8664_LIB64:
186 fputs (",x86-64", stdout);
187 break;
188 case FLAG_S390_LIB64:
189 fputs (",64bit", stdout);
190 break;
191 case FLAG_POWERPC_LIB64:
192 fputs (",64bit", stdout);
193 break;
194 case FLAG_MIPS64_LIBN32:
195 fputs (",N32", stdout);
196 break;
197 case FLAG_MIPS64_LIBN64:
198 fputs (",64bit", stdout);
199 break;
200 case FLAG_X8664_LIBX32:
201 fputs (",x32", stdout);
202 break;
203 case FLAG_ARM_LIBHF:
204 fputs (",hard-float", stdout);
205 break;
206 case FLAG_AARCH64_LIB64:
207 fputs (",AArch64", stdout);
208 break;
209 /* Uses the ARM soft-float ABI. */
210 case FLAG_ARM_LIBSF:
211 fputs (",soft-float", stdout);
212 break;
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;
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;
228 case FLAG_LARCH_FLOAT_ABI_SOFT:
229 fputs (",soft-float", stdout);
230 break;
231 case FLAG_LARCH_FLOAT_ABI_DOUBLE:
232 fputs (",double-float", stdout);
233 break;
234 case 0:
235 break;
236 default:
237 printf (",%d", flag & FLAG_REQUIRED_MASK);
238 break;
240 if (hwcap_string != NULL)
241 printf (", hwcap: \"%s\"", hwcap_string);
242 else if (hwcap != 0)
243 printf (", hwcap: %#.16" PRIx64, hwcap);
244 printf (") => %s\n", key);
247 /* Returns the string with the name of the glibcs-hwcaps subdirectory
248 associated with ENTRY->hwcap. file_base must be the base address
249 for string table indices. */
250 static const char *
251 glibc_hwcaps_string (struct cache_extension_all_loaded *ext,
252 const void *file_base, size_t file_size,
253 struct file_entry_new *entry)
255 const uint32_t *hwcaps_array
256 = ext->sections[cache_extension_tag_glibc_hwcaps].base;
257 if (dl_cache_hwcap_extension (entry) && hwcaps_array != NULL)
259 uint32_t index = (uint32_t) entry->hwcap;
260 if (index < ext->sections[cache_extension_tag_glibc_hwcaps].size / 4)
262 uint32_t string_table_index = hwcaps_array[index];
263 if (string_table_index < file_size)
264 return file_base + string_table_index;
267 return NULL;
270 /* Print an error and exit if the new-file cache is internally
271 inconsistent. */
272 static void
273 check_new_cache (struct cache_file_new *cache)
275 if (! cache_file_new_matches_endian (cache))
276 error (EXIT_FAILURE, 0, _("Cache file has wrong endianness.\n"));
279 /* Print the extension information in *EXT. */
280 static void
281 print_extensions (struct cache_extension_all_loaded *ext)
283 if (ext->sections[cache_extension_tag_generator].base != NULL)
285 fputs (_("Cache generated by: "), stdout);
286 fwrite (ext->sections[cache_extension_tag_generator].base, 1,
287 ext->sections[cache_extension_tag_generator].size, stdout);
288 putchar ('\n');
292 /* Print the whole cache file, if a file contains the new cache format
293 hidden in the old one, print the contents of the new format. */
294 void
295 print_cache (const char *cache_name)
297 int fd = open (cache_name, O_RDONLY);
298 if (fd < 0)
299 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
301 struct stat st;
302 if (fstat (fd, &st) < 0
303 /* No need to map the file if it is empty. */
304 || st.st_size == 0)
306 close (fd);
307 return;
310 struct cache_file *cache
311 = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
312 if (cache == MAP_FAILED)
313 error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
315 size_t cache_size = st.st_size;
316 if (cache_size < sizeof (struct cache_file))
317 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
319 struct cache_file_new *cache_new = NULL;
320 const char *cache_data;
321 int format = 0;
323 if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
325 /* This can only be the new format without the old one. */
326 cache_new = (struct cache_file_new *) cache;
328 if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
329 || memcmp (cache_new->version, CACHE_VERSION,
330 sizeof CACHE_VERSION - 1))
331 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
332 check_new_cache (cache_new);
333 format = 1;
334 /* This is where the strings start. */
335 cache_data = (const char *) cache_new;
337 else
339 /* Check for corruption, avoiding overflow. */
340 if ((cache_size - sizeof (struct cache_file)) / sizeof (struct file_entry)
341 < cache->nlibs)
342 error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
344 size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
345 + (cache->nlibs
346 * sizeof (struct file_entry)));
347 /* This is where the strings start. */
348 cache_data = (const char *) &cache->libs[cache->nlibs];
350 /* Check for a new cache embedded in the old format. */
351 if (cache_size
352 > (offset + sizeof (struct cache_file_new)))
355 cache_new = (struct cache_file_new *) ((void *)cache + offset);
357 if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
358 sizeof CACHEMAGIC_NEW - 1) == 0
359 && memcmp (cache_new->version, CACHE_VERSION,
360 sizeof CACHE_VERSION - 1) == 0)
362 check_new_cache (cache_new);
363 cache_data = (const char *) cache_new;
364 format = 1;
369 if (format == 0)
371 printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
373 /* Print everything. */
374 for (unsigned int i = 0; i < cache->nlibs; i++)
375 print_entry (cache_data + cache->libs[i].key,
376 cache->libs[i].flags, 0, NULL,
377 cache_data + cache->libs[i].value);
379 else if (format == 1)
381 struct cache_extension_all_loaded ext;
382 if (!cache_extension_load (cache_new, cache, cache_size, &ext))
383 error (EXIT_FAILURE, 0,
384 _("Malformed extension data in cache file %s\n"), cache_name);
386 printf (_("%d libs found in cache `%s'\n"),
387 cache_new->nlibs, cache_name);
389 /* Print everything. */
390 for (unsigned int i = 0; i < cache_new->nlibs; i++)
392 const char *hwcaps_string
393 = glibc_hwcaps_string (&ext, cache, cache_size,
394 &cache_new->libs[i]);
395 print_entry (cache_data + cache_new->libs[i].key,
396 cache_new->libs[i].flags,
397 cache_new->libs[i].hwcap, hwcaps_string,
398 cache_data + cache_new->libs[i].value);
400 print_extensions (&ext);
402 /* Cleanup. */
403 munmap (cache, cache_size);
404 close (fd);
407 /* Initialize cache data structures. */
408 void
409 init_cache (void)
411 entries = NULL;
414 static int
415 compare (const struct cache_entry *e1, const struct cache_entry *e2)
417 /* We need to swap entries here to get the correct sort order. */
418 int res = _dl_cache_libcmp (e2->lib->string, e1->lib->string);
419 if (res == 0)
421 if (e1->flags < e2->flags)
422 return 1;
423 else if (e1->flags > e2->flags)
424 return -1;
425 /* Keep the glibc-hwcaps extension entries before the regular
426 entries, and sort them by their names. search_cache in
427 dl-cache.c stops searching once the first non-extension entry
428 is found, so the extension entries need to come first. */
429 else if (e1->hwcaps != NULL && e2->hwcaps == NULL)
430 return -1;
431 else if (e1->hwcaps == NULL && e2->hwcaps != NULL)
432 return 1;
433 else if (e1->hwcaps != NULL && e2->hwcaps != NULL)
435 res = strcmp (glibc_hwcaps_subdirectory_name (e1->hwcaps),
436 glibc_hwcaps_subdirectory_name (e2->hwcaps));
437 if (res != 0)
438 return res;
441 return res;
444 /* Size of the cache extension directory. All tags are assumed to be
445 present. */
446 enum
448 cache_extension_size = (offsetof (struct cache_extension, sections)
449 + (cache_extension_count
450 * sizeof (struct cache_extension_section)))
453 /* Write the cache extensions to FD. The string table is shifted by
454 STRING_TABLE_OFFSET. The extension directory is assumed to be
455 located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices
456 must have been called. */
457 static void
458 write_extensions (int fd, uint32_t str_offset,
459 uint32_t cache_extension_offset)
461 assert ((cache_extension_offset % 4) == 0);
463 /* The length and contents of the glibc-hwcaps section. */
464 uint32_t hwcaps_count = glibc_hwcaps_count ();
465 uint32_t hwcaps_offset = cache_extension_offset + cache_extension_size;
466 uint32_t hwcaps_size = hwcaps_count * sizeof (uint32_t);
467 uint32_t *hwcaps_array = xmalloc (hwcaps_size);
468 for (struct glibc_hwcaps_subdirectory *p = hwcaps; p != NULL; p = p->next)
469 if (p->used)
470 hwcaps_array[p->section_index] = str_offset + p->name->offset;
472 /* This is the offset of the generator string. */
473 uint32_t generator_offset = hwcaps_offset;
474 if (hwcaps_count == 0)
475 /* There is no section for the hwcaps subdirectories. */
476 generator_offset -= sizeof (struct cache_extension_section);
477 else
478 /* The string table indices for the hwcaps subdirectories shift
479 the generator string backwards. */
480 generator_offset += hwcaps_size;
482 struct cache_extension *ext = xmalloc (cache_extension_size);
483 ext->magic = cache_extension_magic;
485 /* Extension index current being filled. */
486 size_t xid = 0;
488 const char *generator
489 = "ldconfig " PKGVERSION RELEASE " release version " VERSION;
490 ext->sections[xid].tag = cache_extension_tag_generator;
491 ext->sections[xid].flags = 0;
492 ext->sections[xid].offset = generator_offset;
493 ext->sections[xid].size = strlen (generator);
495 if (hwcaps_count > 0)
497 ++xid;
498 ext->sections[xid].tag = cache_extension_tag_glibc_hwcaps;
499 ext->sections[xid].flags = 0;
500 ext->sections[xid].offset = hwcaps_offset;
501 ext->sections[xid].size = hwcaps_size;
504 ++xid;
505 ext->count = xid;
506 assert (xid <= cache_extension_count);
508 size_t ext_size = (offsetof (struct cache_extension, sections)
509 + xid * sizeof (struct cache_extension_section));
510 if (write (fd, ext, ext_size) != ext_size
511 || write (fd, hwcaps_array, hwcaps_size) != hwcaps_size
512 || write (fd, generator, strlen (generator)) != strlen (generator))
513 error (EXIT_FAILURE, errno, _("Writing of cache extension data failed"));
515 free (hwcaps_array);
516 free (ext);
519 /* Compute the hwcap value from ENTRY. */
520 static inline uint64_t
521 compute_hwcap_value (struct cache_entry *entry)
523 if (entry->isa_level > DL_CACHE_HWCAP_ISA_LEVEL_MASK)
524 error (EXIT_FAILURE, 0, _("%s: ISA level is too high (%d > %d)"),
525 entry->path->string, entry->isa_level,
526 DL_CACHE_HWCAP_ISA_LEVEL_MASK);
527 return (DL_CACHE_HWCAP_EXTENSION
528 | (((uint64_t) entry->isa_level) << 32)
529 | entry->hwcaps->section_index);
532 /* Save the contents of the cache. */
533 void
534 save_cache (const char *cache_name)
536 /* The cache entries are sorted already, save them in this order. */
538 assign_glibc_hwcaps_indices ();
540 struct cache_entry *entry;
541 /* Number of cache entries. */
542 int cache_entry_count = 0;
543 /* The old format doesn't contain hwcap entries and doesn't contain
544 libraries in subdirectories with hwcaps entries. Count therefore
545 all entries. */
546 int cache_entry_old_count = 0;
548 for (entry = entries; entry != NULL; entry = entry->next)
550 ++cache_entry_count;
551 ++cache_entry_old_count;
554 struct stringtable_finalized strings_finalized;
555 stringtable_finalize (&strings, &strings_finalized);
557 /* Create the on disk cache structure. */
558 struct cache_file *file_entries = NULL;
559 size_t file_entries_size = 0;
561 if (opt_format != opt_format_new)
563 /* struct cache_file_new is 64-bit aligned on some arches while
564 only 32-bit aligned on other arches. Duplicate last old
565 cache entry so that new cache in ld.so.cache can be used by
566 both. */
567 if (opt_format != opt_format_old)
568 cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
570 /* And the list of all entries in the old format. */
571 file_entries_size = sizeof (struct cache_file)
572 + cache_entry_old_count * sizeof (struct file_entry);
573 file_entries = xmalloc (file_entries_size);
575 /* Fill in the header. */
576 memset (file_entries, '\0', sizeof (struct cache_file));
577 memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
579 file_entries->nlibs = cache_entry_old_count;
582 struct cache_file_new *file_entries_new = NULL;
583 size_t file_entries_new_size = 0;
585 if (opt_format != opt_format_old)
587 /* And the list of all entries in the new format. */
588 file_entries_new_size = sizeof (struct cache_file_new)
589 + cache_entry_count * sizeof (struct file_entry_new);
590 file_entries_new = xmalloc (file_entries_new_size);
592 /* Fill in the header. */
593 memset (file_entries_new, '\0', sizeof (struct cache_file_new));
594 memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
595 sizeof CACHEMAGIC_NEW - 1);
596 memcpy (file_entries_new->version, CACHE_VERSION,
597 sizeof CACHE_VERSION - 1);
599 file_entries_new->nlibs = cache_entry_count;
600 file_entries_new->len_strings = strings_finalized.size;
601 file_entries_new->flags = cache_file_new_flags_endian_current;
604 /* Pad for alignment of cache_file_new. */
605 size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
607 /* If we have both formats, we hide the new format in the strings
608 table, we have to adjust all string indices for this so that
609 old libc5/glibc 2 dynamic linkers just ignore them. */
610 unsigned int str_offset;
611 if (opt_format != opt_format_old)
612 str_offset = file_entries_new_size;
613 else
614 str_offset = 0;
616 /* An array for all strings. */
617 int idx_old;
618 int idx_new;
620 for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
621 entry = entry->next, ++idx_new)
623 if (opt_format != opt_format_new)
625 file_entries->libs[idx_old].flags = entry->flags;
626 /* XXX: Actually we can optimize here and remove duplicates. */
627 file_entries->libs[idx_old].key = str_offset + pad;
628 file_entries->libs[idx_new].key = str_offset + entry->lib->offset;
629 file_entries->libs[idx_new].value
630 = str_offset + entry->path->offset;
632 if (opt_format != opt_format_old)
634 /* We could subtract file_entries_new_size from str_offset -
635 not doing so makes the code easier, the string table
636 always begins at the beginning of the new cache
637 struct. */
638 file_entries_new->libs[idx_new].flags = entry->flags;
639 file_entries_new->libs[idx_new].osversion_unused = 0;
640 if (entry->hwcaps == NULL)
641 file_entries_new->libs[idx_new].hwcap = 0;
642 else
643 file_entries_new->libs[idx_new].hwcap
644 = compute_hwcap_value (entry);
645 file_entries_new->libs[idx_new].key
646 = str_offset + entry->lib->offset;
647 file_entries_new->libs[idx_new].value
648 = str_offset + entry->path->offset;
651 ++idx_old;
654 /* Duplicate last old cache entry if needed. */
655 if (opt_format != opt_format_new
656 && idx_old < cache_entry_old_count)
657 file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
659 /* Compute the location of the extension directory. This
660 implementation puts the directory after the string table. The
661 size computation matches the write calls below. The extension
662 directory does not exist with format 0, so the value does not
663 matter. */
664 uint32_t extension_offset = 0;
665 if (opt_format != opt_format_new)
666 extension_offset += file_entries_size;
667 if (opt_format != opt_format_old)
669 if (opt_format != opt_format_new)
670 extension_offset += pad;
671 extension_offset += file_entries_new_size;
673 extension_offset += strings_finalized.size;
674 extension_offset = roundup (extension_offset, 4); /* Provide alignment. */
675 if (opt_format != opt_format_old)
676 file_entries_new->extension_offset = extension_offset;
678 /* Write out the cache. */
680 /* Write cache first to a temporary file and rename it later. */
681 char *temp_name = xmalloc (strlen (cache_name) + 2);
682 sprintf (temp_name, "%s~", cache_name);
684 /* Create file. */
685 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
686 S_IRUSR|S_IWUSR);
687 if (fd < 0)
688 error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
689 temp_name);
691 /* Write contents. */
692 if (opt_format != opt_format_new)
694 if (write (fd, file_entries, file_entries_size)
695 != (ssize_t) file_entries_size)
696 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
698 if (opt_format != opt_format_old)
700 /* Align cache. */
701 if (opt_format != opt_format_new)
703 char zero[pad];
704 memset (zero, '\0', pad);
705 if (write (fd, zero, pad) != (ssize_t) pad)
706 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
708 if (write (fd, file_entries_new, file_entries_new_size)
709 != (ssize_t) file_entries_new_size)
710 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
713 if (write (fd, strings_finalized.strings, strings_finalized.size)
714 != (ssize_t) strings_finalized.size)
715 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
717 if (opt_format != opt_format_old)
719 /* Align file position to 4. */
720 __attribute__ ((unused)) off64_t old_offset
721 = lseek64 (fd, extension_offset, SEEK_SET);
722 assert ((unsigned long long int) (extension_offset - old_offset) < 4);
723 write_extensions (fd, str_offset, extension_offset);
726 /* Make sure user can always read cache file */
727 if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
728 error (EXIT_FAILURE, errno,
729 _("Changing access rights of %s to %#o failed"), temp_name,
730 S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
732 /* Make sure that data is written to disk. */
733 if (fsync (fd) != 0 || close (fd) != 0)
734 error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
736 /* Move temporary to its final location. */
737 if (rename (temp_name, cache_name))
738 error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
739 cache_name);
741 /* Free all allocated memory. */
742 free (file_entries_new);
743 free (file_entries);
744 free (strings_finalized.strings);
745 free (temp_name);
747 while (entries)
749 entry = entries;
750 entries = entries->next;
751 free (entry);
756 /* Add one library to the cache. */
757 void
758 add_to_cache (const char *path, const char *filename, const char *soname,
759 int flags, unsigned int isa_level,
760 struct glibc_hwcaps_subdirectory *hwcaps)
762 struct cache_entry *new_entry = xmalloc (sizeof (*new_entry));
764 struct stringtable_entry *path_interned;
766 char *p;
767 if (asprintf (&p, "%s/%s", path, filename) < 0)
768 error (EXIT_FAILURE, errno, _("Could not create library path"));
769 path_interned = stringtable_add (&strings, p);
770 free (p);
773 new_entry->lib = stringtable_add (&strings, soname);
774 new_entry->path = path_interned;
775 new_entry->flags = flags;
776 new_entry->isa_level = isa_level;
777 new_entry->hwcaps = hwcaps;
779 if (hwcaps != NULL)
780 hwcaps->used = true;
782 /* Keep the list sorted - search for right place to insert. */
783 struct cache_entry *ptr = entries;
784 struct cache_entry *prev = entries;
785 while (ptr != NULL)
787 if (compare (ptr, new_entry) > 0)
788 break;
789 prev = ptr;
790 ptr = ptr->next;
792 /* Is this the first entry? */
793 if (ptr == entries)
795 new_entry->next = entries;
796 entries = new_entry;
798 else
800 new_entry->next = prev->next;
801 prev->next = new_entry;
806 /* Auxiliary cache. */
808 struct aux_cache_entry_id
810 uint64_t ino;
811 uint64_t ctime;
812 uint64_t size;
813 uint64_t dev;
816 struct aux_cache_entry
818 struct aux_cache_entry_id id;
819 int flags;
820 unsigned int isa_level;
821 int used;
822 char *soname;
823 struct aux_cache_entry *next;
826 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
828 struct aux_cache_file_entry
830 struct aux_cache_entry_id id; /* Unique id of entry. */
831 int32_t flags; /* This is 1 for an ELF library. */
832 uint32_t soname; /* String table indice. */
833 uint32_t isa_level; /* Required ISA level. */
836 /* ldconfig maintains an auxiliary cache file that allows
837 only reading those libraries that have changed since the last iteration.
838 For this for each library some information is cached in the auxiliary
839 cache. */
840 struct aux_cache_file
842 char magic[sizeof AUX_CACHEMAGIC - 1];
843 uint32_t nlibs; /* Number of entries. */
844 uint32_t len_strings; /* Size of string table. */
845 struct aux_cache_file_entry libs[0]; /* Entries describing libraries. */
846 /* After this the string table of size len_strings is found. */
849 static const unsigned int primes[] =
851 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
852 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
853 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
856 static size_t aux_hash_size;
857 static struct aux_cache_entry **aux_hash;
859 /* Simplistic hash function for aux_cache_entry_id. */
860 static unsigned int
861 aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
863 uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
864 return ret ^ (ret >> 32);
867 static size_t nextprime (size_t x)
869 for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
870 if (primes[i] >= x)
871 return primes[i];
872 return x;
875 void
876 init_aux_cache (void)
878 aux_hash_size = primes[3];
879 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
883 search_aux_cache (struct stat *stat_buf, int *flags, unsigned int *isa_level,
884 char **soname)
886 struct aux_cache_entry_id id;
887 id.ino = (uint64_t) stat_buf->st_ino;
888 id.ctime = (uint64_t) stat_buf->st_ctime;
889 id.size = (uint64_t) stat_buf->st_size;
890 id.dev = (uint64_t) stat_buf->st_dev;
892 unsigned int hash = aux_cache_entry_id_hash (&id);
893 struct aux_cache_entry *entry;
894 for (entry = aux_hash[hash % aux_hash_size]; entry; entry = entry->next)
895 if (id.ino == entry->id.ino
896 && id.ctime == entry->id.ctime
897 && id.size == entry->id.size
898 && id.dev == entry->id.dev)
900 *flags = entry->flags;
901 *isa_level = entry->isa_level;
902 if (entry->soname != NULL)
903 *soname = xstrdup (entry->soname);
904 else
905 *soname = NULL;
906 entry->used = 1;
907 return 1;
910 return 0;
913 static void
914 insert_to_aux_cache (struct aux_cache_entry_id *id, int flags,
915 unsigned int isa_level, const char *soname, int used)
917 size_t hash = aux_cache_entry_id_hash (id) % aux_hash_size;
918 struct aux_cache_entry *entry;
919 for (entry = aux_hash[hash]; entry; entry = entry->next)
920 if (id->ino == entry->id.ino
921 && id->ctime == entry->id.ctime
922 && id->size == entry->id.size
923 && id->dev == entry->id.dev)
924 abort ();
926 size_t len = soname ? strlen (soname) + 1 : 0;
927 entry = xmalloc (sizeof (struct aux_cache_entry) + len);
928 entry->id = *id;
929 entry->flags = flags;
930 entry->isa_level = isa_level;
931 entry->used = used;
932 if (soname != NULL)
933 entry->soname = memcpy ((char *) (entry + 1), soname, len);
934 else
935 entry->soname = NULL;
936 entry->next = aux_hash[hash];
937 aux_hash[hash] = entry;
940 void
941 add_to_aux_cache (struct stat *stat_buf, int flags, unsigned int isa_level,
942 const char *soname)
944 struct aux_cache_entry_id id;
945 id.ino = (uint64_t) stat_buf->st_ino;
946 id.ctime = (uint64_t) stat_buf->st_ctime;
947 id.size = (uint64_t) stat_buf->st_size;
948 id.dev = (uint64_t) stat_buf->st_dev;
949 insert_to_aux_cache (&id, flags, isa_level, soname, 1);
952 /* Load auxiliary cache to search for unchanged entries. */
953 void
954 load_aux_cache (const char *aux_cache_name)
956 int fd = open (aux_cache_name, O_RDONLY);
957 if (fd < 0)
959 init_aux_cache ();
960 return;
963 struct stat st;
964 if (fstat (fd, &st) < 0 || st.st_size < sizeof (struct aux_cache_file))
966 close (fd);
967 init_aux_cache ();
968 return;
971 size_t aux_cache_size = st.st_size;
972 struct aux_cache_file *aux_cache
973 = mmap (NULL, aux_cache_size, PROT_READ, MAP_PRIVATE, fd, 0);
974 if (aux_cache == MAP_FAILED
975 || aux_cache_size < sizeof (struct aux_cache_file)
976 || memcmp (aux_cache->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1)
977 || aux_cache_size != (sizeof (struct aux_cache_file)
978 + aux_cache->nlibs * sizeof (struct aux_cache_file_entry)
979 + aux_cache->len_strings))
981 if (aux_cache != MAP_FAILED)
982 munmap (aux_cache, aux_cache_size);
984 close (fd);
985 init_aux_cache ();
986 return;
989 aux_hash_size = nextprime (aux_cache->nlibs);
990 aux_hash = xcalloc (aux_hash_size, sizeof (struct aux_cache_entry *));
992 const char *aux_cache_data
993 = (const char *) &aux_cache->libs[aux_cache->nlibs];
994 for (unsigned int i = 0; i < aux_cache->nlibs; ++i)
995 insert_to_aux_cache (&aux_cache->libs[i].id,
996 aux_cache->libs[i].flags,
997 aux_cache->libs[i].isa_level,
998 aux_cache->libs[i].soname == 0
999 ? NULL : aux_cache_data + aux_cache->libs[i].soname,
1002 munmap (aux_cache, aux_cache_size);
1003 close (fd);
1006 /* Save the contents of the auxiliary cache. */
1007 void
1008 save_aux_cache (const char *aux_cache_name)
1010 /* Count the length of all sonames. We start with empty string. */
1011 size_t total_strlen = 1;
1012 /* Number of cache entries. */
1013 int cache_entry_count = 0;
1015 for (size_t i = 0; i < aux_hash_size; ++i)
1016 for (struct aux_cache_entry *entry = aux_hash[i];
1017 entry != NULL; entry = entry->next)
1018 if (entry->used)
1020 ++cache_entry_count;
1021 if (entry->soname != NULL)
1022 total_strlen += strlen (entry->soname) + 1;
1025 /* Auxiliary cache. */
1026 size_t file_entries_size
1027 = sizeof (struct aux_cache_file)
1028 + cache_entry_count * sizeof (struct aux_cache_file_entry);
1029 struct aux_cache_file *file_entries
1030 = xmalloc (file_entries_size + total_strlen);
1032 /* Fill in the header of the auxiliary cache. */
1033 memset (file_entries, '\0', sizeof (struct aux_cache_file));
1034 memcpy (file_entries->magic, AUX_CACHEMAGIC, sizeof AUX_CACHEMAGIC - 1);
1036 file_entries->nlibs = cache_entry_count;
1037 file_entries->len_strings = total_strlen;
1039 /* Initial String offset for auxiliary cache is always after the
1040 special empty string. */
1041 unsigned int str_offset = 1;
1043 /* An array for all strings. */
1044 char *str = (char *) file_entries + file_entries_size;
1045 *str++ = '\0';
1047 size_t idx = 0;
1048 for (size_t i = 0; i < aux_hash_size; ++i)
1049 for (struct aux_cache_entry *entry = aux_hash[i];
1050 entry != NULL; entry = entry->next)
1051 if (entry->used)
1053 file_entries->libs[idx].id = entry->id;
1054 file_entries->libs[idx].flags = entry->flags;
1055 if (entry->soname == NULL)
1056 file_entries->libs[idx].soname = 0;
1057 else
1059 file_entries->libs[idx].soname = str_offset;
1061 size_t len = strlen (entry->soname) + 1;
1062 str = mempcpy (str, entry->soname, len);
1063 str_offset += len;
1065 file_entries->libs[idx++].isa_level = entry->isa_level;
1068 /* Write out auxiliary cache file. */
1069 /* Write auxiliary cache first to a temporary file and rename it later. */
1071 char *temp_name = xmalloc (strlen (aux_cache_name) + 2);
1072 sprintf (temp_name, "%s~", aux_cache_name);
1074 /* Check that directory exists and create if needed. */
1075 char *dir = strdupa (aux_cache_name);
1076 dir = dirname (dir);
1078 struct stat st;
1079 if (stat (dir, &st) < 0)
1081 if (mkdir (dir, 0700) < 0)
1082 goto out_fail;
1085 /* Create file. */
1086 int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
1087 S_IRUSR|S_IWUSR);
1088 if (fd < 0)
1089 goto out_fail;
1091 bool fail = ((write (fd, file_entries, file_entries_size + total_strlen)
1092 != (ssize_t) (file_entries_size + total_strlen))
1093 || fdatasync (fd) != 0);
1095 fail |= close (fd) != 0;
1097 if (fail)
1099 unlink (temp_name);
1100 goto out_fail;
1103 /* Move temporary to its final location. */
1104 if (rename (temp_name, aux_cache_name))
1105 unlink (temp_name);
1107 out_fail:
1108 /* Free allocated memory. */
1109 free (temp_name);
1110 free (file_entries);