1 /* Copyright (C) 1999-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
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.
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.
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/>. */
29 #include <sys/fcntl.h>
32 #include <sys/types.h>
39 char *lib
; /* Library name. */
40 char *path
; /* Path to find library. */
41 int flags
; /* Flags to indicate kind of library. */
42 unsigned int osversion
; /* Required OS version. */
43 uint64_t hwcap
; /* Important hardware capabilities. */
44 int bits_hwcap
; /* Number of bits set in hwcap. */
45 struct cache_entry
*next
; /* Next entry in list. */
48 /* List of all cache entries. */
49 static struct cache_entry
*entries
;
51 static const char *flag_descr
[] =
52 { "libc4", "ELF", "libc5", "libc6"};
54 /* Print a single entry. */
56 print_entry (const char *lib
, int flag
, unsigned int osversion
,
57 uint64_t hwcap
, const char *key
)
59 printf ("\t%s (", lib
);
60 switch (flag
& FLAG_TYPE_MASK
)
66 fputs (flag_descr
[flag
& FLAG_TYPE_MASK
], stdout
);
69 fputs (_("unknown"), stdout
);
72 switch (flag
& FLAG_REQUIRED_MASK
)
74 case FLAG_SPARC_LIB64
:
75 fputs (",64bit", stdout
);
78 fputs (",IA-64", stdout
);
80 case FLAG_X8664_LIB64
:
81 fputs (",x86-64", stdout
);
84 fputs (",64bit", stdout
);
86 case FLAG_POWERPC_LIB64
:
87 fputs (",64bit", stdout
);
89 case FLAG_MIPS64_LIBN32
:
90 fputs (",N32", stdout
);
92 case FLAG_MIPS64_LIBN64
:
93 fputs (",64bit", stdout
);
95 case FLAG_X8664_LIBX32
:
96 fputs (",x32", stdout
);
99 fputs (",hard-float", stdout
);
101 case FLAG_AARCH64_LIB64
:
102 fputs (",AArch64", stdout
);
104 /* Uses the ARM soft-float ABI. */
106 fputs (",soft-float", stdout
);
108 case FLAG_MIPS_LIB32_NAN2008
:
109 fputs (",nan2008", stdout
);
111 case FLAG_MIPS64_LIBN32_NAN2008
:
112 fputs (",N32,nan2008", stdout
);
114 case FLAG_MIPS64_LIBN64_NAN2008
:
115 fputs (",64bit,nan2008", stdout
);
117 case FLAG_RISCV_FLOAT_ABI_SOFT
:
118 fputs (",soft-float", stdout
);
120 case FLAG_RISCV_FLOAT_ABI_DOUBLE
:
121 fputs (",double-float", stdout
);
126 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
130 printf (", hwcap: %#.16" PRIx64
, hwcap
);
133 static const char *const abi_tag_os
[] =
141 [6] = N_("Unknown OS")
143 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
144 unsigned int os
= osversion
>> 24;
146 printf (_(", OS ABI: %s %d.%d.%d"),
147 _(abi_tag_os
[os
> MAXTAG
? MAXTAG
: os
]),
148 (osversion
>> 16) & 0xff,
149 (osversion
>> 8) & 0xff,
152 printf (") => %s\n", key
);
156 /* Print the whole cache file, if a file contains the new cache format
157 hidden in the old one, print the contents of the new format. */
159 print_cache (const char *cache_name
)
161 int fd
= open (cache_name
, O_RDONLY
);
163 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
166 if (fstat64 (fd
, &st
) < 0
167 /* No need to map the file if it is empty. */
174 struct cache_file
*cache
175 = mmap (NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
176 if (cache
== MAP_FAILED
)
177 error (EXIT_FAILURE
, errno
, _("mmap of cache file failed.\n"));
179 size_t cache_size
= st
.st_size
;
180 if (cache_size
< sizeof (struct cache_file
))
181 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
183 struct cache_file_new
*cache_new
= NULL
;
184 const char *cache_data
;
187 if (memcmp (cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
189 /* This can only be the new format without the old one. */
190 cache_new
= (struct cache_file_new
*) cache
;
192 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
193 || memcmp (cache_new
->version
, CACHE_VERSION
,
194 sizeof CACHE_VERSION
- 1))
195 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
197 /* This is where the strings start. */
198 cache_data
= (const char *) cache_new
;
202 /* Check for corruption, avoiding overflow. */
203 if ((cache_size
- sizeof (struct cache_file
)) / sizeof (struct file_entry
)
205 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
207 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
209 * sizeof (struct file_entry
)));
210 /* This is where the strings start. */
211 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
213 /* Check for a new cache embedded in the old format. */
215 > (offset
+ sizeof (struct cache_file_new
)))
218 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
220 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
,
221 sizeof CACHEMAGIC_NEW
- 1) == 0
222 && memcmp (cache_new
->version
, CACHE_VERSION
,
223 sizeof CACHE_VERSION
- 1) == 0)
225 cache_data
= (const char *) cache_new
;
233 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
235 /* Print everything. */
236 for (unsigned int i
= 0; i
< cache
->nlibs
; i
++)
237 print_entry (cache_data
+ cache
->libs
[i
].key
,
238 cache
->libs
[i
].flags
, 0, 0,
239 cache_data
+ cache
->libs
[i
].value
);
241 else if (format
== 1)
243 printf (_("%d libs found in cache `%s'\n"),
244 cache_new
->nlibs
, cache_name
);
246 /* Print everything. */
247 for (unsigned int i
= 0; i
< cache_new
->nlibs
; i
++)
248 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
249 cache_new
->libs
[i
].flags
,
250 cache_new
->libs
[i
].osversion
,
251 cache_new
->libs
[i
].hwcap
,
252 cache_data
+ cache_new
->libs
[i
].value
);
255 munmap (cache
, cache_size
);
259 /* Initialize cache data structures. */
267 compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
269 /* We need to swap entries here to get the correct sort order. */
270 int res
= _dl_cache_libcmp (e2
->lib
, e1
->lib
);
273 if (e1
->flags
< e2
->flags
)
275 else if (e1
->flags
> e2
->flags
)
277 /* Sort by most specific hwcap. */
278 else if (e2
->bits_hwcap
> e1
->bits_hwcap
)
280 else if (e2
->bits_hwcap
< e1
->bits_hwcap
)
282 else if (e2
->hwcap
> e1
->hwcap
)
284 else if (e2
->hwcap
< e1
->hwcap
)
286 if (e2
->osversion
> e1
->osversion
)
288 if (e2
->osversion
< e1
->osversion
)
294 /* Save the contents of the cache. */
296 save_cache (const char *cache_name
)
298 /* The cache entries are sorted already, save them in this order. */
300 /* Count the length of all strings. */
301 /* The old format doesn't contain hwcap entries and doesn't contain
302 libraries in subdirectories with hwcaps entries. Count therefore
303 also all entries with hwcap == 0. */
304 size_t total_strlen
= 0;
305 struct cache_entry
*entry
;
306 /* Number of cache entries. */
307 int cache_entry_count
= 0;
308 /* Number of normal cache entries. */
309 int cache_entry_old_count
= 0;
311 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
313 /* Account the final NULs. */
314 total_strlen
+= strlen (entry
->lib
) + strlen (entry
->path
) + 2;
316 if (entry
->hwcap
== 0)
317 ++cache_entry_old_count
;
320 /* Create the on disk cache structure. */
321 struct cache_file
*file_entries
= NULL
;
322 size_t file_entries_size
= 0;
326 /* struct cache_file_new is 64-bit aligned on some arches while
327 only 32-bit aligned on other arches. Duplicate last old
328 cache entry so that new cache in ld.so.cache can be used by
331 cache_entry_old_count
= (cache_entry_old_count
+ 1) & ~1;
333 /* And the list of all entries in the old format. */
334 file_entries_size
= sizeof (struct cache_file
)
335 + cache_entry_old_count
* sizeof (struct file_entry
);
336 file_entries
= xmalloc (file_entries_size
);
338 /* Fill in the header. */
339 memset (file_entries
, '\0', sizeof (struct cache_file
));
340 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
342 file_entries
->nlibs
= cache_entry_old_count
;
345 struct cache_file_new
*file_entries_new
= NULL
;
346 size_t file_entries_new_size
= 0;
350 /* And the list of all entries in the new format. */
351 file_entries_new_size
= sizeof (struct cache_file_new
)
352 + cache_entry_count
* sizeof (struct file_entry_new
);
353 file_entries_new
= xmalloc (file_entries_new_size
);
355 /* Fill in the header. */
356 memset (file_entries_new
, '\0', sizeof (struct cache_file_new
));
357 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
,
358 sizeof CACHEMAGIC_NEW
- 1);
359 memcpy (file_entries_new
->version
, CACHE_VERSION
,
360 sizeof CACHE_VERSION
- 1);
362 file_entries_new
->nlibs
= cache_entry_count
;
363 file_entries_new
->len_strings
= total_strlen
;
366 /* Pad for alignment of cache_file_new. */
367 size_t pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
369 /* If we have both formats, we hide the new format in the strings
370 table, we have to adjust all string indices for this so that
371 old libc5/glibc 2 dynamic linkers just ignore them. */
372 unsigned int str_offset
;
374 str_offset
= file_entries_new_size
;
378 /* An array for all strings. */
379 char *strings
= xmalloc (total_strlen
);
384 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
385 entry
= entry
->next
, ++idx_new
)
387 /* First the library. */
388 if (opt_format
!= 2 && entry
->hwcap
== 0)
390 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
391 /* XXX: Actually we can optimize here and remove duplicates. */
392 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
396 /* We could subtract file_entries_new_size from str_offset -
397 not doing so makes the code easier, the string table
398 always begins at the beginning of the new cache
400 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
401 file_entries_new
->libs
[idx_new
].osversion
= entry
->osversion
;
402 file_entries_new
->libs
[idx_new
].hwcap
= entry
->hwcap
;
403 file_entries_new
->libs
[idx_new
].key
= str_offset
;
406 size_t len
= strlen (entry
->lib
) + 1;
407 str
= mempcpy (str
, entry
->lib
, len
);
410 if (opt_format
!= 2 && entry
->hwcap
== 0)
411 file_entries
->libs
[idx_old
].value
= str_offset
+ pad
;
413 file_entries_new
->libs
[idx_new
].value
= str_offset
;
414 len
= strlen (entry
->path
) + 1;
415 str
= mempcpy (str
, entry
->path
, len
);
417 /* Ignore entries with hwcap for old format. */
418 if (entry
->hwcap
== 0)
422 /* Duplicate last old cache entry if needed. */
424 && idx_old
< cache_entry_old_count
)
425 file_entries
->libs
[idx_old
] = file_entries
->libs
[idx_old
- 1];
427 /* Write out the cache. */
429 /* Write cache first to a temporary file and rename it later. */
430 char *temp_name
= xmalloc (strlen (cache_name
) + 2);
431 sprintf (temp_name
, "%s~", cache_name
);
434 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
437 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
440 /* Write contents. */
443 if (write (fd
, file_entries
, file_entries_size
)
444 != (ssize_t
) file_entries_size
)
445 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
453 memset (zero
, '\0', pad
);
454 if (write (fd
, zero
, pad
) != (ssize_t
) pad
)
455 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
457 if (write (fd
, file_entries_new
, file_entries_new_size
)
458 != (ssize_t
) file_entries_new_size
)
459 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
462 if (write (fd
, strings
, total_strlen
) != (ssize_t
) total_strlen
)
463 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
465 /* Make sure user can always read cache file */
466 if (chmod (temp_name
, S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
))
467 error (EXIT_FAILURE
, errno
,
468 _("Changing access rights of %s to %#o failed"), temp_name
,
469 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
471 /* Make sure that data is written to disk. */
472 if (fsync (fd
) != 0 || close (fd
) != 0)
473 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
475 /* Move temporary to its final location. */
476 if (rename (temp_name
, cache_name
))
477 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
480 /* Free all allocated memory. */
481 free (file_entries_new
);
488 entries
= entries
->next
;
494 /* Add one library to the cache. */
496 add_to_cache (const char *path
, const char *lib
, int flags
,
497 unsigned int osversion
, uint64_t hwcap
)
499 size_t liblen
= strlen (lib
) + 1;
500 size_t len
= liblen
+ strlen (path
) + 1;
501 struct cache_entry
*new_entry
502 = xmalloc (sizeof (struct cache_entry
) + liblen
+ len
);
504 new_entry
->lib
= memcpy ((char *) (new_entry
+ 1), lib
, liblen
);
505 new_entry
->path
= new_entry
->lib
+ liblen
;
506 snprintf (new_entry
->path
, len
, "%s/%s", path
, lib
);
507 new_entry
->flags
= flags
;
508 new_entry
->osversion
= osversion
;
509 new_entry
->hwcap
= hwcap
;
510 new_entry
->bits_hwcap
= 0;
512 /* Count the number of bits set in the masked value. */
514 (~((1ULL << i
) - 1) & hwcap
) != 0 && i
< 8 * sizeof (hwcap
); ++i
)
515 if ((hwcap
& (1ULL << i
)) != 0)
516 ++new_entry
->bits_hwcap
;
519 /* Keep the list sorted - search for right place to insert. */
520 struct cache_entry
*ptr
= entries
;
521 struct cache_entry
*prev
= entries
;
524 if (compare (ptr
, new_entry
) > 0)
529 /* Is this the first entry? */
532 new_entry
->next
= entries
;
537 new_entry
->next
= prev
->next
;
538 prev
->next
= new_entry
;
543 /* Auxiliary cache. */
545 struct aux_cache_entry_id
553 struct aux_cache_entry
555 struct aux_cache_entry_id id
;
557 unsigned int osversion
;
560 struct aux_cache_entry
*next
;
563 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
565 struct aux_cache_file_entry
567 struct aux_cache_entry_id id
; /* Unique id of entry. */
568 int32_t flags
; /* This is 1 for an ELF library. */
569 uint32_t soname
; /* String table indice. */
570 uint32_t osversion
; /* Required OS version. */
574 /* ldconfig maintains an auxiliary cache file that allows
575 only reading those libraries that have changed since the last iteration.
576 For this for each library some information is cached in the auxiliary
578 struct aux_cache_file
580 char magic
[sizeof AUX_CACHEMAGIC
- 1];
581 uint32_t nlibs
; /* Number of entries. */
582 uint32_t len_strings
; /* Size of string table. */
583 struct aux_cache_file_entry libs
[0]; /* Entries describing libraries. */
584 /* After this the string table of size len_strings is found. */
587 static const unsigned int primes
[] =
589 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
590 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
591 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
594 static size_t aux_hash_size
;
595 static struct aux_cache_entry
**aux_hash
;
597 /* Simplistic hash function for aux_cache_entry_id. */
599 aux_cache_entry_id_hash (struct aux_cache_entry_id
*id
)
601 uint64_t ret
= ((id
->ino
* 11 + id
->ctime
) * 11 + id
->size
) * 11 + id
->dev
;
602 return ret
^ (ret
>> 32);
605 static size_t nextprime (size_t x
)
607 for (unsigned int i
= 0; i
< sizeof (primes
) / sizeof (primes
[0]); ++i
)
614 init_aux_cache (void)
616 aux_hash_size
= primes
[3];
617 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
621 search_aux_cache (struct stat64
*stat_buf
, int *flags
,
622 unsigned int *osversion
, char **soname
)
624 struct aux_cache_entry_id id
;
625 id
.ino
= (uint64_t) stat_buf
->st_ino
;
626 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
627 id
.size
= (uint64_t) stat_buf
->st_size
;
628 id
.dev
= (uint64_t) stat_buf
->st_dev
;
630 unsigned int hash
= aux_cache_entry_id_hash (&id
);
631 struct aux_cache_entry
*entry
;
632 for (entry
= aux_hash
[hash
% aux_hash_size
]; entry
; entry
= entry
->next
)
633 if (id
.ino
== entry
->id
.ino
634 && id
.ctime
== entry
->id
.ctime
635 && id
.size
== entry
->id
.size
636 && id
.dev
== entry
->id
.dev
)
638 *flags
= entry
->flags
;
639 *osversion
= entry
->osversion
;
640 if (entry
->soname
!= NULL
)
641 *soname
= xstrdup (entry
->soname
);
652 insert_to_aux_cache (struct aux_cache_entry_id
*id
, int flags
,
653 unsigned int osversion
, const char *soname
, int used
)
655 size_t hash
= aux_cache_entry_id_hash (id
) % aux_hash_size
;
656 struct aux_cache_entry
*entry
;
657 for (entry
= aux_hash
[hash
]; entry
; entry
= entry
->next
)
658 if (id
->ino
== entry
->id
.ino
659 && id
->ctime
== entry
->id
.ctime
660 && id
->size
== entry
->id
.size
661 && id
->dev
== entry
->id
.dev
)
664 size_t len
= soname
? strlen (soname
) + 1 : 0;
665 entry
= xmalloc (sizeof (struct aux_cache_entry
) + len
);
667 entry
->flags
= flags
;
668 entry
->osversion
= osversion
;
671 entry
->soname
= memcpy ((char *) (entry
+ 1), soname
, len
);
673 entry
->soname
= NULL
;
674 entry
->next
= aux_hash
[hash
];
675 aux_hash
[hash
] = entry
;
679 add_to_aux_cache (struct stat64
*stat_buf
, int flags
,
680 unsigned int osversion
, const char *soname
)
682 struct aux_cache_entry_id id
;
683 id
.ino
= (uint64_t) stat_buf
->st_ino
;
684 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
685 id
.size
= (uint64_t) stat_buf
->st_size
;
686 id
.dev
= (uint64_t) stat_buf
->st_dev
;
687 insert_to_aux_cache (&id
, flags
, osversion
, soname
, 1);
690 /* Load auxiliary cache to search for unchanged entries. */
692 load_aux_cache (const char *aux_cache_name
)
694 int fd
= open (aux_cache_name
, O_RDONLY
);
702 if (fstat64 (fd
, &st
) < 0 || st
.st_size
< sizeof (struct aux_cache_file
))
709 size_t aux_cache_size
= st
.st_size
;
710 struct aux_cache_file
*aux_cache
711 = mmap (NULL
, aux_cache_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
712 if (aux_cache
== MAP_FAILED
713 || aux_cache_size
< sizeof (struct aux_cache_file
)
714 || memcmp (aux_cache
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1)
715 || aux_cache_size
!= (sizeof (struct aux_cache_file
)
716 + aux_cache
->nlibs
* sizeof (struct aux_cache_file_entry
)
717 + aux_cache
->len_strings
))
724 aux_hash_size
= nextprime (aux_cache
->nlibs
);
725 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
727 const char *aux_cache_data
728 = (const char *) &aux_cache
->libs
[aux_cache
->nlibs
];
729 for (unsigned int i
= 0; i
< aux_cache
->nlibs
; ++i
)
730 insert_to_aux_cache (&aux_cache
->libs
[i
].id
,
731 aux_cache
->libs
[i
].flags
,
732 aux_cache
->libs
[i
].osversion
,
733 aux_cache
->libs
[i
].soname
== 0
734 ? NULL
: aux_cache_data
+ aux_cache
->libs
[i
].soname
,
737 munmap (aux_cache
, aux_cache_size
);
741 /* Save the contents of the auxiliary cache. */
743 save_aux_cache (const char *aux_cache_name
)
745 /* Count the length of all sonames. We start with empty string. */
746 size_t total_strlen
= 1;
747 /* Number of cache entries. */
748 int cache_entry_count
= 0;
750 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
751 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
752 entry
!= NULL
; entry
= entry
->next
)
756 if (entry
->soname
!= NULL
)
757 total_strlen
+= strlen (entry
->soname
) + 1;
760 /* Auxiliary cache. */
761 size_t file_entries_size
762 = sizeof (struct aux_cache_file
)
763 + cache_entry_count
* sizeof (struct aux_cache_file_entry
);
764 struct aux_cache_file
*file_entries
765 = xmalloc (file_entries_size
+ total_strlen
);
767 /* Fill in the header of the auxiliary cache. */
768 memset (file_entries
, '\0', sizeof (struct aux_cache_file
));
769 memcpy (file_entries
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1);
771 file_entries
->nlibs
= cache_entry_count
;
772 file_entries
->len_strings
= total_strlen
;
774 /* Initial String offset for auxiliary cache is always after the
775 special empty string. */
776 unsigned int str_offset
= 1;
778 /* An array for all strings. */
779 char *str
= (char *) file_entries
+ file_entries_size
;
783 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
784 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
785 entry
!= NULL
; entry
= entry
->next
)
788 file_entries
->libs
[idx
].id
= entry
->id
;
789 file_entries
->libs
[idx
].flags
= entry
->flags
;
790 if (entry
->soname
== NULL
)
791 file_entries
->libs
[idx
].soname
= 0;
794 file_entries
->libs
[idx
].soname
= str_offset
;
796 size_t len
= strlen (entry
->soname
) + 1;
797 str
= mempcpy (str
, entry
->soname
, len
);
800 file_entries
->libs
[idx
].osversion
= entry
->osversion
;
801 file_entries
->libs
[idx
++].pad
= 0;
804 /* Write out auxiliary cache file. */
805 /* Write auxiliary cache first to a temporary file and rename it later. */
807 char *temp_name
= xmalloc (strlen (aux_cache_name
) + 2);
808 sprintf (temp_name
, "%s~", aux_cache_name
);
810 /* Check that directory exists and create if needed. */
811 char *dir
= strdupa (aux_cache_name
);
815 if (stat64 (dir
, &st
) < 0)
817 if (mkdir (dir
, 0700) < 0)
822 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
827 if (write (fd
, file_entries
, file_entries_size
+ total_strlen
)
828 != (ssize_t
) (file_entries_size
+ total_strlen
)
829 || fdatasync (fd
) != 0
836 /* Move temporary to its final location. */
837 if (rename (temp_name
, aux_cache_name
))
841 /* Free allocated memory. */