1 /* Copyright (C) 1999-2018 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 <http://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 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
204 * sizeof (struct file_entry
)));
205 /* This is where the strings start. */
206 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
208 /* Check for a new cache embedded in the old format. */
210 (offset
+ sizeof (struct cache_file_new
)))
213 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
215 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
,
216 sizeof CACHEMAGIC_NEW
- 1) == 0
217 && memcmp (cache_new
->version
, CACHE_VERSION
,
218 sizeof CACHE_VERSION
- 1) == 0)
220 cache_data
= (const char *) cache_new
;
228 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
230 /* Print everything. */
231 for (unsigned int i
= 0; i
< cache
->nlibs
; i
++)
232 print_entry (cache_data
+ cache
->libs
[i
].key
,
233 cache
->libs
[i
].flags
, 0, 0,
234 cache_data
+ cache
->libs
[i
].value
);
236 else if (format
== 1)
238 printf (_("%d libs found in cache `%s'\n"),
239 cache_new
->nlibs
, cache_name
);
241 /* Print everything. */
242 for (unsigned int i
= 0; i
< cache_new
->nlibs
; i
++)
243 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
244 cache_new
->libs
[i
].flags
,
245 cache_new
->libs
[i
].osversion
,
246 cache_new
->libs
[i
].hwcap
,
247 cache_data
+ cache_new
->libs
[i
].value
);
250 munmap (cache
, cache_size
);
254 /* Initialize cache data structures. */
262 compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
264 /* We need to swap entries here to get the correct sort order. */
265 int res
= _dl_cache_libcmp (e2
->lib
, e1
->lib
);
268 if (e1
->flags
< e2
->flags
)
270 else if (e1
->flags
> e2
->flags
)
272 /* Sort by most specific hwcap. */
273 else if (e2
->bits_hwcap
> e1
->bits_hwcap
)
275 else if (e2
->bits_hwcap
< e1
->bits_hwcap
)
277 else if (e2
->hwcap
> e1
->hwcap
)
279 else if (e2
->hwcap
< e1
->hwcap
)
281 if (e2
->osversion
> e1
->osversion
)
283 if (e2
->osversion
< e1
->osversion
)
289 /* Save the contents of the cache. */
291 save_cache (const char *cache_name
)
293 /* The cache entries are sorted already, save them in this order. */
295 /* Count the length of all strings. */
296 /* The old format doesn't contain hwcap entries and doesn't contain
297 libraries in subdirectories with hwcaps entries. Count therefore
298 also all entries with hwcap == 0. */
299 size_t total_strlen
= 0;
300 struct cache_entry
*entry
;
301 /* Number of cache entries. */
302 int cache_entry_count
= 0;
303 /* Number of normal cache entries. */
304 int cache_entry_old_count
= 0;
306 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
308 /* Account the final NULs. */
309 total_strlen
+= strlen (entry
->lib
) + strlen (entry
->path
) + 2;
311 if (entry
->hwcap
== 0)
312 ++cache_entry_old_count
;
315 /* Create the on disk cache structure. */
316 struct cache_file
*file_entries
= NULL
;
317 size_t file_entries_size
= 0;
321 /* struct cache_file_new is 64-bit aligned on some arches while
322 only 32-bit aligned on other arches. Duplicate last old
323 cache entry so that new cache in ld.so.cache can be used by
326 cache_entry_old_count
= (cache_entry_old_count
+ 1) & ~1;
328 /* And the list of all entries in the old format. */
329 file_entries_size
= sizeof (struct cache_file
)
330 + cache_entry_old_count
* sizeof (struct file_entry
);
331 file_entries
= xmalloc (file_entries_size
);
333 /* Fill in the header. */
334 memset (file_entries
, '\0', sizeof (struct cache_file
));
335 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
337 file_entries
->nlibs
= cache_entry_old_count
;
340 struct cache_file_new
*file_entries_new
= NULL
;
341 size_t file_entries_new_size
= 0;
345 /* And the list of all entries in the new format. */
346 file_entries_new_size
= sizeof (struct cache_file_new
)
347 + cache_entry_count
* sizeof (struct file_entry_new
);
348 file_entries_new
= xmalloc (file_entries_new_size
);
350 /* Fill in the header. */
351 memset (file_entries_new
, '\0', sizeof (struct cache_file_new
));
352 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
,
353 sizeof CACHEMAGIC_NEW
- 1);
354 memcpy (file_entries_new
->version
, CACHE_VERSION
,
355 sizeof CACHE_VERSION
- 1);
357 file_entries_new
->nlibs
= cache_entry_count
;
358 file_entries_new
->len_strings
= total_strlen
;
361 /* Pad for alignment of cache_file_new. */
362 size_t pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
364 /* If we have both formats, we hide the new format in the strings
365 table, we have to adjust all string indices for this so that
366 old libc5/glibc 2 dynamic linkers just ignore them. */
367 unsigned int str_offset
;
369 str_offset
= file_entries_new_size
;
373 /* An array for all strings. */
374 char *strings
= xmalloc (total_strlen
);
379 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
380 entry
= entry
->next
, ++idx_new
)
382 /* First the library. */
383 if (opt_format
!= 2 && entry
->hwcap
== 0)
385 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
386 /* XXX: Actually we can optimize here and remove duplicates. */
387 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
391 /* We could subtract file_entries_new_size from str_offset -
392 not doing so makes the code easier, the string table
393 always begins at the beginning of the new cache
395 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
396 file_entries_new
->libs
[idx_new
].osversion
= entry
->osversion
;
397 file_entries_new
->libs
[idx_new
].hwcap
= entry
->hwcap
;
398 file_entries_new
->libs
[idx_new
].key
= str_offset
;
401 size_t len
= strlen (entry
->lib
) + 1;
402 str
= mempcpy (str
, entry
->lib
, len
);
405 if (opt_format
!= 2 && entry
->hwcap
== 0)
406 file_entries
->libs
[idx_old
].value
= str_offset
+ pad
;
408 file_entries_new
->libs
[idx_new
].value
= str_offset
;
409 len
= strlen (entry
->path
) + 1;
410 str
= mempcpy (str
, entry
->path
, len
);
412 /* Ignore entries with hwcap for old format. */
413 if (entry
->hwcap
== 0)
417 /* Duplicate last old cache entry if needed. */
419 && idx_old
< cache_entry_old_count
)
420 file_entries
->libs
[idx_old
] = file_entries
->libs
[idx_old
- 1];
422 /* Write out the cache. */
424 /* Write cache first to a temporary file and rename it later. */
425 char *temp_name
= xmalloc (strlen (cache_name
) + 2);
426 sprintf (temp_name
, "%s~", cache_name
);
429 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
432 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
435 /* Write contents. */
438 if (write (fd
, file_entries
, file_entries_size
)
439 != (ssize_t
) file_entries_size
)
440 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
448 memset (zero
, '\0', pad
);
449 if (write (fd
, zero
, pad
) != (ssize_t
) pad
)
450 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
452 if (write (fd
, file_entries_new
, file_entries_new_size
)
453 != (ssize_t
) file_entries_new_size
)
454 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
457 if (write (fd
, strings
, total_strlen
) != (ssize_t
) total_strlen
459 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
461 /* Make sure user can always read cache file */
462 if (chmod (temp_name
, S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
))
463 error (EXIT_FAILURE
, errno
,
464 _("Changing access rights of %s to %#o failed"), temp_name
,
465 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
467 /* Move temporary to its final location. */
468 if (rename (temp_name
, cache_name
))
469 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
472 /* Free all allocated memory. */
473 free (file_entries_new
);
480 entries
= entries
->next
;
486 /* Add one library to the cache. */
488 add_to_cache (const char *path
, const char *lib
, int flags
,
489 unsigned int osversion
, uint64_t hwcap
)
491 size_t liblen
= strlen (lib
) + 1;
492 size_t len
= liblen
+ strlen (path
) + 1;
493 struct cache_entry
*new_entry
494 = xmalloc (sizeof (struct cache_entry
) + liblen
+ len
);
496 new_entry
->lib
= memcpy ((char *) (new_entry
+ 1), lib
, liblen
);
497 new_entry
->path
= new_entry
->lib
+ liblen
;
498 snprintf (new_entry
->path
, len
, "%s/%s", path
, lib
);
499 new_entry
->flags
= flags
;
500 new_entry
->osversion
= osversion
;
501 new_entry
->hwcap
= hwcap
;
502 new_entry
->bits_hwcap
= 0;
504 /* Count the number of bits set in the masked value. */
506 (~((1ULL << i
) - 1) & hwcap
) != 0 && i
< 8 * sizeof (hwcap
); ++i
)
507 if ((hwcap
& (1ULL << i
)) != 0)
508 ++new_entry
->bits_hwcap
;
511 /* Keep the list sorted - search for right place to insert. */
512 struct cache_entry
*ptr
= entries
;
513 struct cache_entry
*prev
= entries
;
516 if (compare (ptr
, new_entry
) > 0)
521 /* Is this the first entry? */
524 new_entry
->next
= entries
;
529 new_entry
->next
= prev
->next
;
530 prev
->next
= new_entry
;
535 /* Auxiliary cache. */
537 struct aux_cache_entry_id
545 struct aux_cache_entry
547 struct aux_cache_entry_id id
;
549 unsigned int osversion
;
552 struct aux_cache_entry
*next
;
555 #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
557 struct aux_cache_file_entry
559 struct aux_cache_entry_id id
; /* Unique id of entry. */
560 int32_t flags
; /* This is 1 for an ELF library. */
561 uint32_t soname
; /* String table indice. */
562 uint32_t osversion
; /* Required OS version. */
566 /* ldconfig maintains an auxiliary cache file that allows
567 only reading those libraries that have changed since the last iteration.
568 For this for each library some information is cached in the auxiliary
570 struct aux_cache_file
572 char magic
[sizeof AUX_CACHEMAGIC
- 1];
573 uint32_t nlibs
; /* Number of entries. */
574 uint32_t len_strings
; /* Size of string table. */
575 struct aux_cache_file_entry libs
[0]; /* Entries describing libraries. */
576 /* After this the string table of size len_strings is found. */
579 static const unsigned int primes
[] =
581 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
582 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
583 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
586 static size_t aux_hash_size
;
587 static struct aux_cache_entry
**aux_hash
;
589 /* Simplistic hash function for aux_cache_entry_id. */
591 aux_cache_entry_id_hash (struct aux_cache_entry_id
*id
)
593 uint64_t ret
= ((id
->ino
* 11 + id
->ctime
) * 11 + id
->size
) * 11 + id
->dev
;
594 return ret
^ (ret
>> 32);
597 static size_t nextprime (size_t x
)
599 for (unsigned int i
= 0; i
< sizeof (primes
) / sizeof (primes
[0]); ++i
)
606 init_aux_cache (void)
608 aux_hash_size
= primes
[3];
609 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
613 search_aux_cache (struct stat64
*stat_buf
, int *flags
,
614 unsigned int *osversion
, char **soname
)
616 struct aux_cache_entry_id id
;
617 id
.ino
= (uint64_t) stat_buf
->st_ino
;
618 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
619 id
.size
= (uint64_t) stat_buf
->st_size
;
620 id
.dev
= (uint64_t) stat_buf
->st_dev
;
622 unsigned int hash
= aux_cache_entry_id_hash (&id
);
623 struct aux_cache_entry
*entry
;
624 for (entry
= aux_hash
[hash
% aux_hash_size
]; entry
; entry
= entry
->next
)
625 if (id
.ino
== entry
->id
.ino
626 && id
.ctime
== entry
->id
.ctime
627 && id
.size
== entry
->id
.size
628 && id
.dev
== entry
->id
.dev
)
630 *flags
= entry
->flags
;
631 *osversion
= entry
->osversion
;
632 if (entry
->soname
!= NULL
)
633 *soname
= xstrdup (entry
->soname
);
644 insert_to_aux_cache (struct aux_cache_entry_id
*id
, int flags
,
645 unsigned int osversion
, const char *soname
, int used
)
647 size_t hash
= aux_cache_entry_id_hash (id
) % aux_hash_size
;
648 struct aux_cache_entry
*entry
;
649 for (entry
= aux_hash
[hash
]; entry
; entry
= entry
->next
)
650 if (id
->ino
== entry
->id
.ino
651 && id
->ctime
== entry
->id
.ctime
652 && id
->size
== entry
->id
.size
653 && id
->dev
== entry
->id
.dev
)
656 size_t len
= soname
? strlen (soname
) + 1 : 0;
657 entry
= xmalloc (sizeof (struct aux_cache_entry
) + len
);
659 entry
->flags
= flags
;
660 entry
->osversion
= osversion
;
663 entry
->soname
= memcpy ((char *) (entry
+ 1), soname
, len
);
665 entry
->soname
= NULL
;
666 entry
->next
= aux_hash
[hash
];
667 aux_hash
[hash
] = entry
;
671 add_to_aux_cache (struct stat64
*stat_buf
, int flags
,
672 unsigned int osversion
, const char *soname
)
674 struct aux_cache_entry_id id
;
675 id
.ino
= (uint64_t) stat_buf
->st_ino
;
676 id
.ctime
= (uint64_t) stat_buf
->st_ctime
;
677 id
.size
= (uint64_t) stat_buf
->st_size
;
678 id
.dev
= (uint64_t) stat_buf
->st_dev
;
679 insert_to_aux_cache (&id
, flags
, osversion
, soname
, 1);
682 /* Load auxiliary cache to search for unchanged entries. */
684 load_aux_cache (const char *aux_cache_name
)
686 int fd
= open (aux_cache_name
, O_RDONLY
);
694 if (fstat64 (fd
, &st
) < 0 || st
.st_size
< sizeof (struct aux_cache_file
))
701 size_t aux_cache_size
= st
.st_size
;
702 struct aux_cache_file
*aux_cache
703 = mmap (NULL
, aux_cache_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
704 if (aux_cache
== MAP_FAILED
705 || aux_cache_size
< sizeof (struct aux_cache_file
)
706 || memcmp (aux_cache
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1)
707 || aux_cache_size
!= (sizeof(struct aux_cache_file
) +
708 aux_cache
->nlibs
* sizeof(struct aux_cache_file_entry
) +
709 aux_cache
->len_strings
))
716 aux_hash_size
= nextprime (aux_cache
->nlibs
);
717 aux_hash
= xcalloc (aux_hash_size
, sizeof (struct aux_cache_entry
*));
719 const char *aux_cache_data
720 = (const char *) &aux_cache
->libs
[aux_cache
->nlibs
];
721 for (unsigned int i
= 0; i
< aux_cache
->nlibs
; ++i
)
722 insert_to_aux_cache (&aux_cache
->libs
[i
].id
,
723 aux_cache
->libs
[i
].flags
,
724 aux_cache
->libs
[i
].osversion
,
725 aux_cache
->libs
[i
].soname
== 0
726 ? NULL
: aux_cache_data
+ aux_cache
->libs
[i
].soname
,
729 munmap (aux_cache
, aux_cache_size
);
733 /* Save the contents of the auxiliary cache. */
735 save_aux_cache (const char *aux_cache_name
)
737 /* Count the length of all sonames. We start with empty string. */
738 size_t total_strlen
= 1;
739 /* Number of cache entries. */
740 int cache_entry_count
= 0;
742 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
743 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
744 entry
!= NULL
; entry
= entry
->next
)
748 if (entry
->soname
!= NULL
)
749 total_strlen
+= strlen (entry
->soname
) + 1;
752 /* Auxiliary cache. */
753 size_t file_entries_size
754 = sizeof (struct aux_cache_file
)
755 + cache_entry_count
* sizeof (struct aux_cache_file_entry
);
756 struct aux_cache_file
*file_entries
757 = xmalloc (file_entries_size
+ total_strlen
);
759 /* Fill in the header of the auxiliary cache. */
760 memset (file_entries
, '\0', sizeof (struct aux_cache_file
));
761 memcpy (file_entries
->magic
, AUX_CACHEMAGIC
, sizeof AUX_CACHEMAGIC
- 1);
763 file_entries
->nlibs
= cache_entry_count
;
764 file_entries
->len_strings
= total_strlen
;
766 /* Initial String offset for auxiliary cache is always after the
767 special empty string. */
768 unsigned int str_offset
= 1;
770 /* An array for all strings. */
771 char *str
= (char *) file_entries
+ file_entries_size
;
775 for (size_t i
= 0; i
< aux_hash_size
; ++i
)
776 for (struct aux_cache_entry
*entry
= aux_hash
[i
];
777 entry
!= NULL
; entry
= entry
->next
)
780 file_entries
->libs
[idx
].id
= entry
->id
;
781 file_entries
->libs
[idx
].flags
= entry
->flags
;
782 if (entry
->soname
== NULL
)
783 file_entries
->libs
[idx
].soname
= 0;
786 file_entries
->libs
[idx
].soname
= str_offset
;
788 size_t len
= strlen (entry
->soname
) + 1;
789 str
= mempcpy (str
, entry
->soname
, len
);
792 file_entries
->libs
[idx
].osversion
= entry
->osversion
;
793 file_entries
->libs
[idx
++].pad
= 0;
796 /* Write out auxiliary cache file. */
797 /* Write auxiliary cache first to a temporary file and rename it later. */
799 char *temp_name
= xmalloc (strlen (aux_cache_name
) + 2);
800 sprintf (temp_name
, "%s~", aux_cache_name
);
802 /* Check that directory exists and create if needed. */
803 char *dir
= strdupa (aux_cache_name
);
807 if (stat64 (dir
, &st
) < 0)
809 if (mkdir (dir
, 0700) < 0)
814 int fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
819 if (write (fd
, file_entries
, file_entries_size
+ total_strlen
)
820 != (ssize_t
) (file_entries_size
+ total_strlen
)
827 /* Move temporary to its final location. */
828 if (rename (temp_name
, aux_cache_name
))
832 /* Free allocated memory. */