1 /* Copyright (C) 1999-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 subdirecty 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
);
231 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
234 if (hwcap_string
!= NULL
)
235 printf (", hwcap: \"%s\"", hwcap_string
);
237 printf (", hwcap: %#.16" PRIx64
, hwcap
);
238 printf (") => %s\n", key
);
241 /* Returns the string with the name of the glibcs-hwcaps subdirectory
242 associated with ENTRY->hwcap. file_base must be the base address
243 for string table indices. */
245 glibc_hwcaps_string (struct cache_extension_all_loaded
*ext
,
246 const void *file_base
, size_t file_size
,
247 struct file_entry_new
*entry
)
249 const uint32_t *hwcaps_array
250 = ext
->sections
[cache_extension_tag_glibc_hwcaps
].base
;
251 if (dl_cache_hwcap_extension (entry
) && hwcaps_array
!= NULL
)
253 uint32_t index
= (uint32_t) entry
->hwcap
;
254 if (index
< ext
->sections
[cache_extension_tag_glibc_hwcaps
].size
/ 4)
256 uint32_t string_table_index
= hwcaps_array
[index
];
257 if (string_table_index
< file_size
)
258 return file_base
+ string_table_index
;
264 /* Print an error and exit if the new-file cache is internally
267 check_new_cache (struct cache_file_new
*cache
)
269 if (! cache_file_new_matches_endian (cache
))
270 error (EXIT_FAILURE
, 0, _("Cache file has wrong endianness.\n"));
273 /* Print the extension information in *EXT. */
275 print_extensions (struct cache_extension_all_loaded
*ext
)
277 if (ext
->sections
[cache_extension_tag_generator
].base
!= NULL
)
279 fputs (_("Cache generated by: "), stdout
);
280 fwrite (ext
->sections
[cache_extension_tag_generator
].base
, 1,
281 ext
->sections
[cache_extension_tag_generator
].size
, stdout
);
286 /* Print the whole cache file, if a file contains the new cache format
287 hidden in the old one, print the contents of the new format. */
289 print_cache (const char *cache_name
)
291 int fd
= open (cache_name
, O_RDONLY
);
293 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
296 if (fstat (fd
, &st
) < 0
297 /* No need to map the file if it is empty. */
304 struct cache_file
*cache
305 = mmap (NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
306 if (cache
== MAP_FAILED
)
307 error (EXIT_FAILURE
, errno
, _("mmap of cache file failed.\n"));
309 size_t cache_size
= st
.st_size
;
310 if (cache_size
< sizeof (struct cache_file
))
311 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
313 struct cache_file_new
*cache_new
= NULL
;
314 const char *cache_data
;
317 if (memcmp (cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
319 /* This can only be the new format without the old one. */
320 cache_new
= (struct cache_file_new
*) cache
;
322 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
323 || memcmp (cache_new
->version
, CACHE_VERSION
,
324 sizeof CACHE_VERSION
- 1))
325 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
326 check_new_cache (cache_new
);
328 /* This is where the strings start. */
329 cache_data
= (const char *) cache_new
;
333 /* Check for corruption, avoiding overflow. */
334 if ((cache_size
- sizeof (struct cache_file
)) / sizeof (struct file_entry
)
336 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
338 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
340 * sizeof (struct file_entry
)));
341 /* This is where the strings start. */
342 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
344 /* Check for a new cache embedded in the old format. */
346 > (offset
+ sizeof (struct cache_file_new
)))
349 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
351 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
,
352 sizeof CACHEMAGIC_NEW
- 1) == 0
353 && memcmp (cache_new
->version
, CACHE_VERSION
,
354 sizeof CACHE_VERSION
- 1) == 0)
356 check_new_cache (cache_new
);
357 cache_data
= (const char *) cache_new
;
365 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
367 /* Print everything. */
368 for (unsigned int i
= 0; i
< cache
->nlibs
; i
++)
369 print_entry (cache_data
+ cache
->libs
[i
].key
,
370 cache
->libs
[i
].flags
, 0, NULL
,
371 cache_data
+ cache
->libs
[i
].value
);
373 else if (format
== 1)
375 struct cache_extension_all_loaded ext
;
376 if (!cache_extension_load (cache_new
, cache
, cache_size
, &ext
))
377 error (EXIT_FAILURE
, 0,
378 _("Malformed extension data in cache file %s\n"), cache_name
);
380 printf (_("%d libs found in cache `%s'\n"),
381 cache_new
->nlibs
, cache_name
);
383 /* Print everything. */
384 for (unsigned int i
= 0; i
< cache_new
->nlibs
; i
++)
386 const char *hwcaps_string
387 = glibc_hwcaps_string (&ext
, cache
, cache_size
,
388 &cache_new
->libs
[i
]);
389 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
390 cache_new
->libs
[i
].flags
,
391 cache_new
->libs
[i
].hwcap
, hwcaps_string
,
392 cache_data
+ cache_new
->libs
[i
].value
);
394 print_extensions (&ext
);
397 munmap (cache
, cache_size
);
401 /* Initialize cache data structures. */
409 compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
411 /* We need to swap entries here to get the correct sort order. */
412 int res
= _dl_cache_libcmp (e2
->lib
->string
, e1
->lib
->string
);
415 if (e1
->flags
< e2
->flags
)
417 else if (e1
->flags
> e2
->flags
)
419 /* Keep the glibc-hwcaps extension entries before the regular
420 entries, and sort them by their names. search_cache in
421 dl-cache.c stops searching once the first non-extension entry
422 is found, so the extension entries need to come first. */
423 else if (e1
->hwcaps
!= NULL
&& e2
->hwcaps
== NULL
)
425 else if (e1
->hwcaps
== NULL
&& e2
->hwcaps
!= NULL
)
427 else if (e1
->hwcaps
!= NULL
&& e2
->hwcaps
!= NULL
)
429 res
= strcmp (glibc_hwcaps_subdirectory_name (e1
->hwcaps
),
430 glibc_hwcaps_subdirectory_name (e2
->hwcaps
));
438 /* Size of the cache extension directory. All tags are assumed to be
442 cache_extension_size
= (offsetof (struct cache_extension
, sections
)
443 + (cache_extension_count
444 * sizeof (struct cache_extension_section
)))
447 /* Write the cache extensions to FD. The string table is shifted by
448 STRING_TABLE_OFFSET. The extension directory is assumed to be
449 located at CACHE_EXTENSION_OFFSET. assign_glibc_hwcaps_indices
450 must have been called. */
452 write_extensions (int fd
, uint32_t str_offset
,
453 uint32_t cache_extension_offset
)
455 assert ((cache_extension_offset
% 4) == 0);
457 /* The length and contents of the glibc-hwcaps section. */
458 uint32_t hwcaps_count
= glibc_hwcaps_count ();
459 uint32_t hwcaps_offset
= cache_extension_offset
+ cache_extension_size
;
460 uint32_t hwcaps_size
= hwcaps_count
* sizeof (uint32_t);
461 uint32_t *hwcaps_array
= xmalloc (hwcaps_size
);
462 for (struct glibc_hwcaps_subdirectory
*p
= hwcaps
; p
!= NULL
; p
= p
->next
)
464 hwcaps_array
[p
->section_index
] = str_offset
+ p
->name
->offset
;
466 /* This is the offset of the generator string. */
467 uint32_t generator_offset
= hwcaps_offset
;
468 if (hwcaps_count
== 0)
469 /* There is no section for the hwcaps subdirectories. */
470 generator_offset
-= sizeof (struct cache_extension_section
);
472 /* The string table indices for the hwcaps subdirectories shift
473 the generator string backwards. */
474 generator_offset
+= hwcaps_size
;
476 struct cache_extension
*ext
= xmalloc (cache_extension_size
);
477 ext
->magic
= cache_extension_magic
;
479 /* Extension index current being filled. */
482 const char *generator
483 = "ldconfig " PKGVERSION RELEASE
" release version " VERSION
;
484 ext
->sections
[xid
].tag
= cache_extension_tag_generator
;
485 ext
->sections
[xid
].flags
= 0;
486 ext
->sections
[xid
].offset
= generator_offset
;
487 ext
->sections
[xid
].size
= strlen (generator
);
489 if (hwcaps_count
> 0)
492 ext
->sections
[xid
].tag
= cache_extension_tag_glibc_hwcaps
;
493 ext
->sections
[xid
].flags
= 0;
494 ext
->sections
[xid
].offset
= hwcaps_offset
;
495 ext
->sections
[xid
].size
= hwcaps_size
;
500 assert (xid
<= cache_extension_count
);
502 size_t ext_size
= (offsetof (struct cache_extension
, sections
)
503 + xid
* sizeof (struct cache_extension_section
));
504 if (write (fd
, ext
, ext_size
) != ext_size
505 || write (fd
, hwcaps_array
, hwcaps_size
) != hwcaps_size
506 || write (fd
, generator
, strlen (generator
)) != strlen (generator
))
507 error (EXIT_FAILURE
, errno
, _("Writing of cache extension data failed"));
513 /* Compute the hwcap value from ENTRY. */
514 static inline uint64_t
515 compute_hwcap_value (struct cache_entry
*entry
)
517 if (entry
->isa_level
> DL_CACHE_HWCAP_ISA_LEVEL_MASK
)
518 error (EXIT_FAILURE
, 0, _("%s: ISA level is too high (%d > %d)"),
519 entry
->path
->string
, entry
->isa_level
,
520 DL_CACHE_HWCAP_ISA_LEVEL_MASK
);
521 return (DL_CACHE_HWCAP_EXTENSION
522 | (((uint64_t) entry
->isa_level
) << 32)
523 | entry
->hwcaps
->section_index
);
526 /* Save the contents of the cache. */
528 save_cache (const char *cache_name
)
530 /* The cache entries are sorted already, save them in this order. */
532 assign_glibc_hwcaps_indices ();
534 struct cache_entry
*entry
;
535 /* Number of cache entries. */
536 int cache_entry_count
= 0;
537 /* The old format doesn't contain hwcap entries and doesn't contain
538 libraries in subdirectories with hwcaps entries. Count therefore
540 int cache_entry_old_count
= 0;
542 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
545 ++cache_entry_old_count
;
548 struct stringtable_finalized strings_finalized
;
549 stringtable_finalize (&strings
, &strings_finalized
);
551 /* Create the on disk cache structure. */
552 struct cache_file
*file_entries
= NULL
;
553 size_t file_entries_size
= 0;
555 if (opt_format
!= opt_format_new
)
557 /* struct cache_file_new is 64-bit aligned on some arches while
558 only 32-bit aligned on other arches. Duplicate last old
559 cache entry so that new cache in ld.so.cache can be used by
561 if (opt_format
!= opt_format_old
)
562 cache_entry_old_count
= (cache_entry_old_count
+ 1) & ~1;
564 /* And the list of all entries in the old format. */
565 file_entries_size
= sizeof (struct cache_file
)
566 + cache_entry_old_count
* sizeof (struct file_entry
);
567 file_entries
= xmalloc (file_entries_size
);
569 /* Fill in the header. */
570 memset (file_entries
, '\0', sizeof (struct cache_file
));
571 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
573 file_entries
->nlibs
= cache_entry_old_count
;
576 struct cache_file_new
*file_entries_new
= NULL
;
577 size_t file_entries_new_size
= 0;
579 if (opt_format
!= opt_format_old
)
581 /* And the list of all entries in the new format. */
582 file_entries_new_size
= sizeof (struct cache_file_new
)
583 + cache_entry_count
* sizeof (struct file_entry_new
);
584 file_entries_new
= xmalloc (file_entries_new_size
);
586 /* Fill in the header. */
587 memset (file_entries_new
, '\0', sizeof (struct cache_file_new
));
588 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
,
589 sizeof CACHEMAGIC_NEW
- 1);
590 memcpy (file_entries_new
->version
, CACHE_VERSION
,
591 sizeof CACHE_VERSION
- 1);
593 file_entries_new
->nlibs
= cache_entry_count
;
594 file_entries_new
->len_strings
= strings_finalized
.size
;
595 file_entries_new
->flags
= cache_file_new_flags_endian_current
;
598 /* Pad for alignment of cache_file_new. */
599 size_t pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
601 /* If we have both formats, we hide the new format in the strings
602 table, we have to adjust all string indices for this so that
603 old libc5/glibc 2 dynamic linkers just ignore them. */
604 unsigned int str_offset
;
605 if (opt_format
!= opt_format_old
)
606 str_offset
= file_entries_new_size
;
610 /* An array for all strings. */
614 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
615 entry
= entry
->next
, ++idx_new
)
617 if (opt_format
!= opt_format_new
)
619 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
620 /* XXX: Actually we can optimize here and remove duplicates. */
621 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
622 file_entries
->libs
[idx_new
].key
= str_offset
+ entry
->lib
->offset
;
623 file_entries
->libs
[idx_new
].value
624 = str_offset
+ entry
->path
->offset
;
626 if (opt_format
!= opt_format_old
)
628 /* We could subtract file_entries_new_size from str_offset -
629 not doing so makes the code easier, the string table
630 always begins at the beginning of the new cache
632 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
633 file_entries_new
->libs
[idx_new
].osversion_unused
= 0;
634 if (entry
->hwcaps
== NULL
)
635 file_entries_new
->libs
[idx_new
].hwcap
= 0;
637 file_entries_new
->libs
[idx_new
].hwcap
638 = compute_hwcap_value (entry
);
639 file_entries_new
->libs
[idx_new
].key
640 = str_offset
+ entry
->lib
->offset
;
641 file_entries_new
->libs
[idx_new
].value
642 = str_offset
+ entry
->path
->offset
;
648 /* Duplicate last old cache entry if needed. */
649 if (opt_format
!= opt_format_new
650 && idx_old
< cache_entry_old_count
)
651 file_entries
->libs
[idx_old
] = file_entries
->libs
[idx_old
- 1];
653 /* Compute the location of the extension directory. This
654 implementation puts the directory after the string table. The
655 size computation matches the write calls below. The extension
656 directory does not exist with format 0, so the value does not
658 uint32_t extension_offset
= 0;
659 if (opt_format
!= opt_format_new
)
660 extension_offset
+= file_entries_size
;
661 if (opt_format
!= opt_format_old
)
663 if (opt_format
!= opt_format_new
)
664 extension_offset
+= pad
;
665 extension_offset
+= file_entries_new_size
;
667 extension_offset
+= strings_finalized
.size
;
668 extension_offset
= roundup (extension_offset
, 4); /* Provide alignment. */
669 if (opt_format
!= opt_format_old
)
670 file_entries_new
->extension_offset
= extension_offset
;
672 /* Write out the cache. */
674 /* Write cache first to a temporary file and rename it later. */
675 char *temp_name
= xmalloc (strlen (cache_name
) + 2);
676 sprintf (temp_name
, "%s~", cache_name
);
679 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
682 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
685 /* Write contents. */
686 if (opt_format
!= opt_format_new
)
688 if (write (fd
, file_entries
, file_entries_size
)
689 != (ssize_t
) file_entries_size
)
690 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
692 if (opt_format
!= opt_format_old
)
695 if (opt_format
!= opt_format_new
)
698 memset (zero
, '\0', pad
);
699 if (write (fd
, zero
, pad
) != (ssize_t
) pad
)
700 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
702 if (write (fd
, file_entries_new
, file_entries_new_size
)
703 != (ssize_t
) file_entries_new_size
)
704 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
707 if (write (fd
, strings_finalized
.strings
, strings_finalized
.size
)
708 != (ssize_t
) strings_finalized
.size
)
709 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
711 if (opt_format
!= opt_format_old
)
713 /* Align file position to 4. */
714 __attribute__ ((unused
)) off64_t old_offset
715 = lseek64 (fd
, extension_offset
, SEEK_SET
);
716 assert ((unsigned long long int) (extension_offset
- old_offset
) < 4);
717 write_extensions (fd
, str_offset
, extension_offset
);
720 /* Make sure user can always read cache file */
721 if (chmod (temp_name
, S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
))
722 error (EXIT_FAILURE
, errno
,
723 _("Changing access rights of %s to %#o failed"), temp_name
,
724 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
726 /* Make sure that data is written to disk. */
727 if (fsync (fd
) != 0 || close (fd
) != 0)
728 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
730 /* Move temporary to its final location. */
731 if (rename (temp_name
, cache_name
))
732 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
735 /* Free all allocated memory. */
736 free (file_entries_new
);
738 free (strings_finalized
.strings
);
744 entries
= entries
->next
;
750 /* Add one library to the cache. */
752 add_to_cache (const char *path
, const char *filename
, const char *soname
,
753 int flags
, unsigned int isa_level
,
754 struct glibc_hwcaps_subdirectory
*hwcaps
)
756 struct cache_entry
*new_entry
= xmalloc (sizeof (*new_entry
));
758 struct stringtable_entry
*path_interned
;
761 if (asprintf (&p
, "%s/%s", path
, filename
) < 0)
762 error (EXIT_FAILURE
, errno
, _("Could not create library path"));
763 path_interned
= stringtable_add (&strings
, p
);
767 new_entry
->lib
= stringtable_add (&strings
, soname
);
768 new_entry
->path
= path_interned
;
769 new_entry
->flags
= flags
;
770 new_entry
->isa_level
= isa_level
;
771 new_entry
->hwcaps
= hwcaps
;
776 /* Keep the list sorted - search for right place to insert. */
777 struct cache_entry
*ptr
= entries
;
778 struct cache_entry
*prev
= entries
;
781 if (compare (ptr
, new_entry
) > 0)
786 /* Is this the first entry? */
789 new_entry
->next
= entries
;
794 new_entry
->next
= prev
->next
;
795 prev
->next
= new_entry
;
800 /* Auxiliary cache. */
802 struct aux_cache_entry_id
810 struct aux_cache_entry
812 struct aux_cache_entry_id id
;
814 unsigned int isa_level
;
817 struct aux_cache_entry
*next
;
820 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
822 struct aux_cache_file_entry
824 struct aux_cache_entry_id id
; /* Unique id of entry. */
825 int32_t flags
; /* This is 1 for an ELF library. */
826 uint32_t soname
; /* String table indice. */
827 uint32_t isa_level
; /* Required ISA level. */
830 /* ldconfig maintains an auxiliary cache file that allows
831 only reading those libraries that have changed since the last iteration.
832 For this for each library some information is cached in the auxiliary
834 struct aux_cache_file
836 char magic
[sizeof AUX_CACHEMAGIC
- 1];
837 uint32_t nlibs
; /* Number of entries. */
838 uint32_t len_strings
; /* Size of string table. */
839 struct aux_cache_file_entry libs
[0]; /* Entries describing libraries. */
840 /* After this the string table of size len_strings is found. */
843 static const unsigned int primes
[] =
845 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
846 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
847 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
850 static size_t aux_hash_size
;
851 static struct aux_cache_entry
**aux_hash
;
853 /* Simplistic hash function for aux_cache_entry_id. */
855 aux_cache_entry_id_hash (struct aux_cache_entry_id
*id
)
857 uint64_t ret
= ((id
->ino
* 11 + id
->ctime
) * 11 + id
->size
) * 11 + id
->dev
;
858 return ret
^ (ret
>> 32);
861 static size_t nextprime (size_t x
)
863 for (unsigned int i
= 0; i
< sizeof (primes
) / sizeof (primes
[0]); ++i
)
870 init_aux_cache (void)
872 aux_hash_size
= primes
[3];
873 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
877 search_aux_cache (struct stat
*stat_buf
, int *flags
, unsigned int *isa_level
,
880 struct aux_cache_entry_id id
;
881 id
.ino
= (uint64_t) stat_buf
->st_ino
;
882 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
883 id
.size
= (uint64_t) stat_buf
->st_size
;
884 id
.dev
= (uint64_t) stat_buf
->st_dev
;
886 unsigned int hash
= aux_cache_entry_id_hash (&id
);
887 struct aux_cache_entry
*entry
;
888 for (entry
= aux_hash
[hash
% aux_hash_size
]; entry
; entry
= entry
->next
)
889 if (id
.ino
== entry
->id
.ino
890 && id
.ctime
== entry
->id
.ctime
891 && id
.size
== entry
->id
.size
892 && id
.dev
== entry
->id
.dev
)
894 *flags
= entry
->flags
;
895 *isa_level
= entry
->isa_level
;
896 if (entry
->soname
!= NULL
)
897 *soname
= xstrdup (entry
->soname
);
908 insert_to_aux_cache (struct aux_cache_entry_id
*id
, int flags
,
909 unsigned int isa_level
, const char *soname
, int used
)
911 size_t hash
= aux_cache_entry_id_hash (id
) % aux_hash_size
;
912 struct aux_cache_entry
*entry
;
913 for (entry
= aux_hash
[hash
]; entry
; entry
= entry
->next
)
914 if (id
->ino
== entry
->id
.ino
915 && id
->ctime
== entry
->id
.ctime
916 && id
->size
== entry
->id
.size
917 && id
->dev
== entry
->id
.dev
)
920 size_t len
= soname
? strlen (soname
) + 1 : 0;
921 entry
= xmalloc (sizeof (struct aux_cache_entry
) + len
);
923 entry
->flags
= flags
;
924 entry
->isa_level
= isa_level
;
927 entry
->soname
= memcpy ((char *) (entry
+ 1), soname
, len
);
929 entry
->soname
= NULL
;
930 entry
->next
= aux_hash
[hash
];
931 aux_hash
[hash
] = entry
;
935 add_to_aux_cache (struct stat
*stat_buf
, int flags
, unsigned int isa_level
,
938 struct aux_cache_entry_id id
;
939 id
.ino
= (uint64_t) stat_buf
->st_ino
;
940 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
941 id
.size
= (uint64_t) stat_buf
->st_size
;
942 id
.dev
= (uint64_t) stat_buf
->st_dev
;
943 insert_to_aux_cache (&id
, flags
, isa_level
, soname
, 1);
946 /* Load auxiliary cache to search for unchanged entries. */
948 load_aux_cache (const char *aux_cache_name
)
950 int fd
= open (aux_cache_name
, O_RDONLY
);
958 if (fstat (fd
, &st
) < 0 || st
.st_size
< sizeof (struct aux_cache_file
))
965 size_t aux_cache_size
= st
.st_size
;
966 struct aux_cache_file
*aux_cache
967 = mmap (NULL
, aux_cache_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
968 if (aux_cache
== MAP_FAILED
969 || aux_cache_size
< sizeof (struct aux_cache_file
)
970 || memcmp (aux_cache
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1)
971 || aux_cache_size
!= (sizeof (struct aux_cache_file
)
972 + aux_cache
->nlibs
* sizeof (struct aux_cache_file_entry
)
973 + aux_cache
->len_strings
))
975 if (aux_cache
!= MAP_FAILED
)
976 munmap (aux_cache
, aux_cache_size
);
983 aux_hash_size
= nextprime (aux_cache
->nlibs
);
984 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
986 const char *aux_cache_data
987 = (const char *) &aux_cache
->libs
[aux_cache
->nlibs
];
988 for (unsigned int i
= 0; i
< aux_cache
->nlibs
; ++i
)
989 insert_to_aux_cache (&aux_cache
->libs
[i
].id
,
990 aux_cache
->libs
[i
].flags
,
991 aux_cache
->libs
[i
].isa_level
,
992 aux_cache
->libs
[i
].soname
== 0
993 ? NULL
: aux_cache_data
+ aux_cache
->libs
[i
].soname
,
996 munmap (aux_cache
, aux_cache_size
);
1000 /* Save the contents of the auxiliary cache. */
1002 save_aux_cache (const char *aux_cache_name
)
1004 /* Count the length of all sonames. We start with empty string. */
1005 size_t total_strlen
= 1;
1006 /* Number of cache entries. */
1007 int cache_entry_count
= 0;
1009 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
1010 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
1011 entry
!= NULL
; entry
= entry
->next
)
1014 ++cache_entry_count
;
1015 if (entry
->soname
!= NULL
)
1016 total_strlen
+= strlen (entry
->soname
) + 1;
1019 /* Auxiliary cache. */
1020 size_t file_entries_size
1021 = sizeof (struct aux_cache_file
)
1022 + cache_entry_count
* sizeof (struct aux_cache_file_entry
);
1023 struct aux_cache_file
*file_entries
1024 = xmalloc (file_entries_size
+ total_strlen
);
1026 /* Fill in the header of the auxiliary cache. */
1027 memset (file_entries
, '\0', sizeof (struct aux_cache_file
));
1028 memcpy (file_entries
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1);
1030 file_entries
->nlibs
= cache_entry_count
;
1031 file_entries
->len_strings
= total_strlen
;
1033 /* Initial String offset for auxiliary cache is always after the
1034 special empty string. */
1035 unsigned int str_offset
= 1;
1037 /* An array for all strings. */
1038 char *str
= (char *) file_entries
+ file_entries_size
;
1042 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
1043 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
1044 entry
!= NULL
; entry
= entry
->next
)
1047 file_entries
->libs
[idx
].id
= entry
->id
;
1048 file_entries
->libs
[idx
].flags
= entry
->flags
;
1049 if (entry
->soname
== NULL
)
1050 file_entries
->libs
[idx
].soname
= 0;
1053 file_entries
->libs
[idx
].soname
= str_offset
;
1055 size_t len
= strlen (entry
->soname
) + 1;
1056 str
= mempcpy (str
, entry
->soname
, len
);
1059 file_entries
->libs
[idx
++].isa_level
= entry
->isa_level
;
1062 /* Write out auxiliary cache file. */
1063 /* Write auxiliary cache first to a temporary file and rename it later. */
1065 char *temp_name
= xmalloc (strlen (aux_cache_name
) + 2);
1066 sprintf (temp_name
, "%s~", aux_cache_name
);
1068 /* Check that directory exists and create if needed. */
1069 char *dir
= strdupa (aux_cache_name
);
1070 dir
= dirname (dir
);
1073 if (stat (dir
, &st
) < 0)
1075 if (mkdir (dir
, 0700) < 0)
1080 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
1085 bool fail
= ((write (fd
, file_entries
, file_entries_size
+ total_strlen
)
1086 != (ssize_t
) (file_entries_size
+ total_strlen
))
1087 || fdatasync (fd
) != 0);
1089 fail
|= close (fd
) != 0;
1097 /* Move temporary to its final location. */
1098 if (rename (temp_name
, aux_cache_name
))
1102 /* Free allocated memory. */
1104 free (file_entries
);