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