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/>. */
29 #include <sys/fcntl.h>
31 #include <sys/param.h>
33 #include <sys/types.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
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. */
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
)
79 struct glibc_hwcaps_subdirectory
*p
= xmalloc (sizeof (*p
));
81 p
->name
= name_interned
;
88 /* Helper for sorting struct glibc_hwcaps_subdirectory elements by
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
104 glibc_hwcaps_count (void)
107 for (struct glibc_hwcaps_subdirectory
*p
= hwcaps
; p
!= NULL
; p
= p
->next
)
113 /* Compute the section_index fields for all */
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
);
124 for (struct glibc_hwcaps_subdirectory
*p
= hwcaps
; p
!= NULL
; p
= p
->next
)
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
;
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. */
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
)
171 fputs (flag_descr
[flag
& FLAG_TYPE_MASK
], stdout
);
174 fputs (_("unknown or unsupported flag"), stdout
);
177 switch (flag
& FLAG_REQUIRED_MASK
)
179 case FLAG_SPARC_LIB64
:
180 fputs (",64bit", stdout
);
182 case FLAG_IA64_LIB64
:
183 fputs (",IA-64", stdout
);
185 case FLAG_X8664_LIB64
:
186 fputs (",x86-64", stdout
);
188 case FLAG_S390_LIB64
:
189 fputs (",64bit", stdout
);
191 case FLAG_POWERPC_LIB64
:
192 fputs (",64bit", stdout
);
194 case FLAG_MIPS64_LIBN32
:
195 fputs (",N32", stdout
);
197 case FLAG_MIPS64_LIBN64
:
198 fputs (",64bit", stdout
);
200 case FLAG_X8664_LIBX32
:
201 fputs (",x32", stdout
);
204 fputs (",hard-float", stdout
);
206 case FLAG_AARCH64_LIB64
:
207 fputs (",AArch64", stdout
);
209 /* Uses the ARM soft-float ABI. */
211 fputs (",soft-float", stdout
);
213 case FLAG_MIPS_LIB32_NAN2008
:
214 fputs (",nan2008", stdout
);
216 case FLAG_MIPS64_LIBN32_NAN2008
:
217 fputs (",N32,nan2008", stdout
);
219 case FLAG_MIPS64_LIBN64_NAN2008
:
220 fputs (",64bit,nan2008", stdout
);
222 case FLAG_RISCV_FLOAT_ABI_SOFT
:
223 fputs (",soft-float", stdout
);
225 case FLAG_RISCV_FLOAT_ABI_DOUBLE
:
226 fputs (",double-float", stdout
);
228 case FLAG_LARCH_FLOAT_ABI_SOFT
:
229 fputs (",soft-float", stdout
);
231 case FLAG_LARCH_FLOAT_ABI_DOUBLE
:
232 fputs (",double-float", stdout
);
237 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
240 if (hwcap_string
!= NULL
)
241 printf (", hwcap: \"%s\"", hwcap_string
);
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. */
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
;
270 /* Print an error and exit if the new-file cache is internally
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. */
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
);
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. */
295 print_cache (const char *cache_name
)
297 int fd
= open (cache_name
, O_RDONLY
);
299 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
302 if (fstat (fd
, &st
) < 0
303 /* No need to map the file if it is empty. */
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
;
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
);
334 /* This is where the strings start. */
335 cache_data
= (const char *) cache_new
;
339 /* Check for corruption, avoiding overflow. */
340 if ((cache_size
- sizeof (struct cache_file
)) / sizeof (struct file_entry
)
342 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
344 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
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. */
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
;
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
);
403 munmap (cache
, cache_size
);
407 /* Initialize cache data structures. */
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
);
421 if (e1
->flags
< e2
->flags
)
423 else if (e1
->flags
> e2
->flags
)
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
)
431 else if (e1
->hwcaps
== NULL
&& e2
->hwcaps
!= NULL
)
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
));
444 /* Size of the cache extension directory. All tags are assumed to be
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. */
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
)
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
);
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. */
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)
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
;
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"));
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. */
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
546 int cache_entry_old_count
= 0;
548 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
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
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
;
616 /* An array for all strings. */
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
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;
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
;
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
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
);
685 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
688 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
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
)
701 if (opt_format
!= opt_format_new
)
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
,
741 /* Free all allocated memory. */
742 free (file_entries_new
);
744 free (strings_finalized
.strings
);
750 entries
= entries
->next
;
756 /* Add one library to the cache. */
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
;
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
);
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
;
782 /* Keep the list sorted - search for right place to insert. */
783 struct cache_entry
*ptr
= entries
;
784 struct cache_entry
*prev
= entries
;
787 if (compare (ptr
, new_entry
) > 0)
792 /* Is this the first entry? */
795 new_entry
->next
= entries
;
800 new_entry
->next
= prev
->next
;
801 prev
->next
= new_entry
;
806 /* Auxiliary cache. */
808 struct aux_cache_entry_id
816 struct aux_cache_entry
818 struct aux_cache_entry_id id
;
820 unsigned int isa_level
;
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
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. */
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
)
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
,
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
);
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
)
926 size_t len
= soname
? strlen (soname
) + 1 : 0;
927 entry
= xmalloc (sizeof (struct aux_cache_entry
) + len
);
929 entry
->flags
= flags
;
930 entry
->isa_level
= isa_level
;
933 entry
->soname
= memcpy ((char *) (entry
+ 1), soname
, len
);
935 entry
->soname
= NULL
;
936 entry
->next
= aux_hash
[hash
];
937 aux_hash
[hash
] = entry
;
941 add_to_aux_cache (struct stat
*stat_buf
, int flags
, unsigned int isa_level
,
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. */
954 load_aux_cache (const char *aux_cache_name
)
956 int fd
= open (aux_cache_name
, O_RDONLY
);
964 if (fstat (fd
, &st
) < 0 || st
.st_size
< sizeof (struct aux_cache_file
))
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
);
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
);
1006 /* Save the contents of the auxiliary cache. */
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
)
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
;
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
)
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;
1059 file_entries
->libs
[idx
].soname
= str_offset
;
1061 size_t len
= strlen (entry
->soname
) + 1;
1062 str
= mempcpy (str
, entry
->soname
, 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
);
1079 if (stat (dir
, &st
) < 0)
1081 if (mkdir (dir
, 0700) < 0)
1086 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
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;
1103 /* Move temporary to its final location. */
1104 if (rename (temp_name
, aux_cache_name
))
1108 /* Free allocated memory. */
1110 free (file_entries
);