1 /* Copyright (C) 1999,2000,2001,2002,2003,2005
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
30 #include <sys/fcntl.h>
33 #include <sys/types.h>
40 char *lib
; /* Library name. */
41 char *path
; /* Path to find library. */
42 int flags
; /* Flags to indicate kind of library. */
43 unsigned int osversion
; /* Required OS version. */
44 uint64_t hwcap
; /* Important hardware capabilities. */
45 int bits_hwcap
; /* Number of bits set in hwcap. */
46 struct cache_entry
*next
; /* Next entry in list. */
49 /* List of all cache entries. */
50 static struct cache_entry
*entries
;
52 static const char *flag_descr
[] =
53 { "libc4", "ELF", "libc5", "libc6"};
55 /* Print a single entry. */
57 print_entry (const char *lib
, int flag
, unsigned int osversion
,
58 uint64_t hwcap
, const char *key
)
60 printf ("\t%s (", lib
);
61 switch (flag
& FLAG_TYPE_MASK
)
67 fputs (flag_descr
[flag
& FLAG_TYPE_MASK
], stdout
);
70 fputs (_("unknown"), stdout
);
73 switch (flag
& FLAG_REQUIRED_MASK
)
75 case FLAG_SPARC_LIB64
:
76 fputs (",64bit", stdout
);
79 fputs (",IA-64", stdout
);
81 case FLAG_X8664_LIB64
:
82 fputs (",x86-64", stdout
);
85 fputs(",64bit", stdout
);
87 case FLAG_POWERPC_LIB64
:
88 fputs(",64bit", stdout
);
90 case FLAG_MIPS64_LIBN32
:
91 fputs(",N32", stdout
);
93 case FLAG_MIPS64_LIBN64
:
94 fputs(",64bit", stdout
);
98 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
102 printf (", hwcap: %#.16" PRIx64
, hwcap
);
105 static const char *const abi_tag_os
[] =
112 [5] = N_("Unknown OS")
114 #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
115 unsigned int os
= osversion
>> 24;
117 printf (_(", OS ABI: %s %d.%d.%d"),
118 _(abi_tag_os
[os
> MAXTAG
? MAXTAG
: os
]),
119 (osversion
>> 16) & 0xff,
120 (osversion
>> 8) & 0xff,
123 printf (") => %s\n", key
);
127 /* Print the whole cache file, if a file contains the new cache format
128 hidden in the old one, print the contents of the new format. */
130 print_cache (const char *cache_name
)
136 struct cache_file
*cache
;
137 struct cache_file_new
*cache_new
= NULL
;
138 const char *cache_data
;
141 fd
= open (cache_name
, O_RDONLY
);
143 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
145 if (fstat64 (fd
, &st
) < 0
146 /* No need to map the file if it is empty. */
153 cache
= mmap (0, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
154 if (cache
== MAP_FAILED
)
155 error (EXIT_FAILURE
, errno
, _("mmap of cache file failed.\n"));
156 cache_size
= st
.st_size
;
158 if (cache_size
< sizeof (struct cache_file
))
159 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
161 if (memcmp (cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
163 /* This can only be the new format without the old one. */
164 cache_new
= (struct cache_file_new
*) cache
;
166 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
167 || memcmp (cache_new
->version
, CACHE_VERSION
,
168 sizeof CACHE_VERSION
- 1))
169 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
171 /* This is where the strings start. */
172 cache_data
= (const char *) cache_new
;
176 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
178 * sizeof (struct file_entry
)));
179 /* This is where the strings start. */
180 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
182 /* Check for a new cache embedded in the old format. */
184 (offset
+ sizeof (struct cache_file_new
)))
187 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
189 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
,
190 sizeof CACHEMAGIC_NEW
- 1) == 0
191 && memcmp (cache_new
->version
, CACHE_VERSION
,
192 sizeof CACHE_VERSION
- 1) == 0)
194 cache_data
= (const char *) cache_new
;
202 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
204 /* Print everything. */
205 for (i
= 0; i
< cache
->nlibs
; i
++)
206 print_entry (cache_data
+ cache
->libs
[i
].key
,
207 cache
->libs
[i
].flags
, 0, 0,
208 cache_data
+ cache
->libs
[i
].value
);
210 else if (format
== 1)
212 printf (_("%d libs found in cache `%s'\n"),
213 cache_new
->nlibs
, cache_name
);
215 /* Print everything. */
216 for (i
= 0; i
< cache_new
->nlibs
; i
++)
217 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
218 cache_new
->libs
[i
].flags
,
219 cache_new
->libs
[i
].osversion
,
220 cache_new
->libs
[i
].hwcap
,
221 cache_data
+ cache_new
->libs
[i
].value
);
224 munmap (cache
, cache_size
);
228 /* Initialize cache data structures. */
238 int compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
242 /* We need to swap entries here to get the correct sort order. */
243 res
= _dl_cache_libcmp (e2
->lib
, e1
->lib
);
246 if (e1
->flags
< e2
->flags
)
248 else if (e1
->flags
> e2
->flags
)
250 /* Sort by most specific hwcap. */
251 else if (e2
->bits_hwcap
> e1
->bits_hwcap
)
253 else if (e2
->bits_hwcap
< e1
->bits_hwcap
)
255 else if (e2
->hwcap
> e1
->hwcap
)
257 else if (e2
->hwcap
< e1
->hwcap
)
259 if (e2
->osversion
> e1
->osversion
)
261 if (e2
->osversion
< e1
->osversion
)
267 /* Save the contents of the cache. */
269 save_cache (const char *cache_name
)
271 struct cache_entry
*entry
;
272 int fd
, idx_old
, idx_new
;
273 size_t total_strlen
, len
;
274 char *strings
, *str
, *temp_name
;
275 struct cache_file
*file_entries
= NULL
;
276 struct cache_file_new
*file_entries_new
= NULL
;
277 size_t file_entries_size
= 0;
278 size_t file_entries_new_size
= 0;
279 unsigned int str_offset
;
280 /* Number of cache entries. */
281 int cache_entry_count
= 0;
282 /* Number of normal cache entries. */
283 int cache_entry_old_count
= 0;
284 /* Pad for alignment of cache_file_new. */
287 /* The cache entries are sorted already, save them in this order. */
289 /* Count the length of all strings. */
290 /* The old format doesn't contain hwcap entries and doesn't contain
291 libraries in subdirectories with hwcaps entries. Count therefore
292 also all entries with hwcap == 0. */
294 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
296 /* Account the final NULs. */
297 total_strlen
+= strlen (entry
->lib
) + strlen (entry
->path
) + 2;
299 if (entry
->hwcap
== 0)
300 ++cache_entry_old_count
;
303 /* Create the on disk cache structure. */
304 /* First an array for all strings. */
305 strings
= (char *)xmalloc (total_strlen
);
309 /* struct cache_file_new is 64-bit aligned on some arches while
310 only 32-bit aligned on other arches. Duplicate last old
311 cache entry so that new cache in ld.so.cache can be used by
314 cache_entry_old_count
= (cache_entry_old_count
+ 1) & ~1;
316 /* And the list of all entries in the old format. */
317 file_entries_size
= sizeof (struct cache_file
)
318 + cache_entry_old_count
* sizeof (struct file_entry
);
319 file_entries
= (struct cache_file
*) xmalloc (file_entries_size
);
321 /* Fill in the header. */
322 memset (file_entries
, 0, sizeof (struct cache_file
));
323 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
325 file_entries
->nlibs
= cache_entry_old_count
;
330 /* And the list of all entries in the new format. */
331 file_entries_new_size
= sizeof (struct cache_file_new
)
332 + cache_entry_count
* sizeof (struct file_entry_new
);
334 (struct cache_file_new
*) xmalloc (file_entries_new_size
);
336 /* Fill in the header. */
337 memset (file_entries_new
, 0, sizeof (struct cache_file_new
));
338 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
,
339 sizeof CACHEMAGIC_NEW
- 1);
340 memcpy (file_entries_new
->version
, CACHE_VERSION
,
341 sizeof CACHE_VERSION
- 1);
343 file_entries_new
->nlibs
= cache_entry_count
;
344 file_entries_new
->len_strings
= total_strlen
;
347 pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
349 /* If we have both formats, we hide the new format in the strings
350 table, we have to adjust all string indices for this so that
351 old libc5/glibc 2 dynamic linkers just ignore them. */
353 str_offset
= file_entries_new_size
;
358 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
359 entry
= entry
->next
, ++idx_new
)
361 /* First the library. */
362 if (opt_format
!= 2 && entry
->hwcap
== 0)
364 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
365 /* XXX: Actually we can optimize here and remove duplicates. */
366 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
370 /* We could subtract file_entries_new_size from str_offset -
371 not doing so makes the code easier, the string table
372 always begins at the beginning of the the new cache
374 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
375 file_entries_new
->libs
[idx_new
].osversion
= entry
->osversion
;
376 file_entries_new
->libs
[idx_new
].hwcap
= entry
->hwcap
;
377 file_entries_new
->libs
[idx_new
].key
= str_offset
;
379 len
= strlen (entry
->lib
);
380 str
= stpcpy (str
, entry
->lib
);
381 /* Account the final NUL. */
383 str_offset
+= len
+ 1;
385 if (opt_format
!= 2 && entry
->hwcap
== 0)
386 file_entries
->libs
[idx_old
].value
= str_offset
+ pad
;
388 file_entries_new
->libs
[idx_new
].value
= str_offset
;
389 len
= strlen (entry
->path
);
390 str
= stpcpy (str
, entry
->path
);
391 /* Account the final NUL. */
393 str_offset
+= len
+ 1;
394 /* Ignore entries with hwcap for old format. */
395 if (entry
->hwcap
== 0)
399 /* Duplicate last old cache entry if needed. */
401 && idx_old
< cache_entry_old_count
)
402 file_entries
->libs
[idx_old
] = file_entries
->libs
[idx_old
- 1];
404 /* Write out the cache. */
406 /* Write cache first to a temporary file and rename it later. */
407 temp_name
= xmalloc (strlen (cache_name
) + 2);
408 sprintf (temp_name
, "%s~", cache_name
);
409 /* First remove an old copy if it exists. */
410 if (unlink (temp_name
) && errno
!= ENOENT
)
411 error (EXIT_FAILURE
, errno
, _("Can't remove old temporary cache file %s"),
415 fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
,
416 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
418 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
421 /* Write contents. */
424 if (write (fd
, file_entries
, file_entries_size
)
425 != (ssize_t
)file_entries_size
)
426 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
434 if (write (fd
, zero
, pad
) != (ssize_t
)pad
)
435 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
437 if (write (fd
, file_entries_new
, file_entries_new_size
)
438 != (ssize_t
)file_entries_new_size
)
439 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
442 if (write (fd
, strings
, total_strlen
) != (ssize_t
)total_strlen
)
443 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed."));
447 /* Make sure user can always read cache file */
448 if (chmod (temp_name
, S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
))
449 error (EXIT_FAILURE
, errno
,
450 _("Changing access rights of %s to %#o failed"), temp_name
,
451 S_IROTH
|S_IRGRP
|S_IRUSR
|S_IWUSR
);
453 /* Move temporary to its final location. */
454 if (rename (temp_name
, cache_name
))
455 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
458 /* Free all allocated memory. */
467 entries
= entries
->next
;
473 /* Add one library to the cache. */
475 add_to_cache (const char *path
, const char *lib
, int flags
,
476 unsigned int osversion
, uint64_t hwcap
)
478 struct cache_entry
*new_entry
, *ptr
, *prev
;
482 new_entry
= (struct cache_entry
*) xmalloc (sizeof (struct cache_entry
));
484 len
= strlen (lib
) + strlen (path
) + 2;
486 full_path
= (char *) xmalloc (len
);
487 snprintf (full_path
, len
, "%s/%s", path
, lib
);
489 new_entry
->lib
= xstrdup (lib
);
490 new_entry
->path
= full_path
;
491 new_entry
->flags
= flags
;
492 new_entry
->osversion
= osversion
;
493 new_entry
->hwcap
= hwcap
;
494 new_entry
->bits_hwcap
= 0;
496 /* Count the number of bits set in the masked value. */
497 for (i
= 0; (~((1ULL << i
) - 1) & hwcap
) != 0 && i
< 8 * sizeof (hwcap
); ++i
)
498 if ((hwcap
& (1ULL << i
)) != 0)
499 ++new_entry
->bits_hwcap
;
502 /* Keep the list sorted - search for right place to insert. */
507 if (compare (ptr
, new_entry
) > 0)
512 /* Is this the first entry? */
515 new_entry
->next
= entries
;
520 new_entry
->next
= prev
->next
;
521 prev
->next
= new_entry
;