1 /* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Andreas Jaeger <aj@suse.de>, 1999.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library 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 GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
28 #include <sys/fcntl.h>
31 #include <sys/types.h>
38 char *lib
; /* Library name. */
39 char *path
; /* Path to find library. */
40 int flags
; /* Flags to indicate kind of library. */
41 unsigned long int hwcap
; /* Important hardware capabilities. */
42 int bits_hwcap
; /* Number of bits set in hwcap. */
43 struct cache_entry
*next
; /* Next entry in list. */
46 /* List of all cache entries. */
47 static struct cache_entry
*entries
;
49 static const char *flag_descr
[] =
50 { "libc4", "ELF", "libc5", "libc6"};
52 /* Print a single entry. */
54 print_entry (const char *lib
, int flag
, unsigned long int hwcap
, const char *key
)
56 printf ("\t%s (", lib
);
57 switch (flag
& FLAG_TYPE_MASK
)
63 fputs (flag_descr
[flag
& FLAG_TYPE_MASK
], stdout
);
66 fputs ("unknown", stdout
);
69 switch (flag
& FLAG_REQUIRED_MASK
)
72 case FLAG_SPARC_LIB64
:
73 fputs (",64bit", stdout
);
78 printf (",%d", flag
& FLAG_REQUIRED_MASK
);
82 printf (", hwcap: 0x%lx", hwcap
);
83 printf (") => %s\n", key
);
87 /* Print the whole cache file, if a file contains the new cache format
88 hidden in the old one, print the contents of the new format. */
90 print_cache (const char *cache_name
)
96 struct cache_file
*cache
;
97 struct cache_file_new
*cache_new
= NULL
;
98 const char *cache_data
;
101 fd
= open (cache_name
, O_RDONLY
);
103 error (EXIT_FAILURE
, errno
, _("Can't open cache file %s\n"), cache_name
);
105 if (fstat (fd
, &st
) < 0
106 /* No need to map the file if it is empty. */
113 cache
= mmap (0, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
114 if (cache
== MAP_FAILED
)
115 error (EXIT_FAILURE
, errno
, _("mmap of cache file failed.\n"));
116 cache_size
= st
.st_size
;
118 if (cache_size
< sizeof (struct cache_file
))
119 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
121 if (memcmp (cache
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1))
123 /* This can only be the new format without the old one. */
124 cache_new
= (struct cache_file_new
*) cache
;
126 if (memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
127 || memcmp (cache_new
->version
, CACHE_VERSION
,
128 sizeof CACHE_VERSION
- 1))
129 error (EXIT_FAILURE
, 0, _("File is not a cache file.\n"));
131 /* This is where the strings start. */
132 cache_data
= (const char *) cache_new
;
136 size_t offset
= ALIGN_CACHE (sizeof (struct cache_file
)
137 + cache
->nlibs
* sizeof (struct file_entry
));
138 /* This is where the strings start. */
139 cache_data
= (const char *) &cache
->libs
[cache
->nlibs
];
141 /* Check for a new cache embedded in the old format. */
143 (offset
+ sizeof (struct cache_file_new
)))
146 cache_new
= (struct cache_file_new
*) ((void *)cache
+ offset
);
148 if (!memcmp (cache_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1)
149 && !memcmp (cache_new
->version
, CACHE_VERSION
,
150 sizeof CACHE_VERSION
- 1))
152 cache_data
= (const char *) cache_new
;
160 printf (_("%d libs found in cache `%s'\n"), cache
->nlibs
, cache_name
);
162 /* Print everything. */
163 for (i
= 0; i
< cache
->nlibs
; i
++)
164 print_entry (cache_data
+ cache
->libs
[i
].key
,
165 cache
->libs
[i
].flags
, 0,
166 cache_data
+ cache
->libs
[i
].value
);
168 else if (format
== 1)
170 printf (_("%d libs found in cache `%s'\n"), cache_new
->nlibs
, cache_name
);
172 /* Print everything. */
173 for (i
= 0; i
< cache_new
->nlibs
; i
++)
174 print_entry (cache_data
+ cache_new
->libs
[i
].key
,
175 cache_new
->libs
[i
].flags
,
176 cache_new
->libs
[i
].hwcap
,
177 cache_data
+ cache_new
->libs
[i
].value
);
180 munmap (cache
, cache_size
);
184 /* Initialize cache data structures. */
194 int compare (const struct cache_entry
*e1
, const struct cache_entry
*e2
)
198 /* We need to swap entries here to get the correct sort order. */
199 res
= _dl_cache_libcmp (e2
->lib
, e1
->lib
);
202 if (e1
->flags
< e2
->flags
)
204 else if (e1
->flags
> e2
->flags
)
206 /* Sort by most specific hwcap. */
207 else if (e2
->bits_hwcap
> e1
->bits_hwcap
)
209 else if (e2
->bits_hwcap
< e1
->bits_hwcap
)
211 else if (e2
->hwcap
> e1
->hwcap
)
213 else if (e2
->hwcap
< e1
->hwcap
)
219 /* Save the contents of the cache. */
221 save_cache (const char *cache_name
)
223 struct cache_entry
*entry
;
224 int fd
, idx_old
, idx_new
;
225 size_t total_strlen
, len
;
226 char *strings
, *str
, *temp_name
;
227 struct cache_file
*file_entries
= NULL
;
228 struct cache_file_new
*file_entries_new
= NULL
;
229 size_t file_entries_size
= 0;
230 size_t file_entries_new_size
= 0;
231 unsigned int str_offset
;
232 /* Number of cache entries. */
233 int cache_entry_count
= 0;
234 /* Number of normal cache entries. */
235 int cache_entry_old_count
= 0;
236 /* Pad for alignment of cache_file_new. */
239 /* The cache entries are sorted already, save them in this order. */
241 /* Count the length of all strings. */
242 /* The old format doesn't contain hwcap entries and doesn't contain
243 libraries in subdirectories with hwcaps entries. Count therefore
244 also all entries with hwcap == 0. */
246 for (entry
= entries
; entry
!= NULL
; entry
= entry
->next
)
248 /* Account the final NULs. */
249 total_strlen
+= strlen (entry
->lib
) + strlen (entry
->path
) + 2;
251 if (entry
->hwcap
== 0)
252 ++cache_entry_old_count
;
255 /* Create the on disk cache structure. */
256 /* First an array for all strings. */
257 strings
= (char *)xmalloc (total_strlen
);
261 /* And the list of all entries in the old format. */
262 file_entries_size
= sizeof (struct cache_file
)
263 + cache_entry_old_count
* sizeof (struct file_entry
);
264 file_entries
= (struct cache_file
*) xmalloc (file_entries_size
);
266 /* Fill in the header. */
267 memset (file_entries
, 0, sizeof (struct cache_file
));
268 memcpy (file_entries
->magic
, CACHEMAGIC
, sizeof CACHEMAGIC
- 1);
270 file_entries
->nlibs
= cache_entry_old_count
;
275 /* And the list of all entries in the new format. */
276 file_entries_new_size
= sizeof (struct cache_file_new
)
277 + cache_entry_count
* sizeof (struct file_entry_new
);
278 file_entries_new
= (struct cache_file_new
*) xmalloc (file_entries_new_size
);
280 /* Fill in the header. */
281 memset (file_entries_new
, 0, sizeof (struct cache_file_new
));
282 memcpy (file_entries_new
->magic
, CACHEMAGIC_NEW
, sizeof CACHEMAGIC_NEW
- 1);
283 memcpy (file_entries_new
->version
, CACHE_VERSION
, sizeof CACHE_VERSION
- 1);
285 file_entries_new
->nlibs
= cache_entry_count
;
286 file_entries_new
->len_strings
= total_strlen
;
289 pad
= ALIGN_CACHE (file_entries_size
) - file_entries_size
;
291 /* If we have both formats, we hide the new format in the strings
292 table, we have to adjust all string indices for this so that
293 old libc5/glibc 2 dynamic linkers just ignore them. */
295 str_offset
= file_entries_new_size
;
300 for (idx_old
= 0, idx_new
= 0, entry
= entries
; entry
!= NULL
;
301 entry
= entry
->next
, ++idx_new
)
303 /* First the library. */
306 file_entries
->libs
[idx_old
].flags
= entry
->flags
;
307 /* XXX: Actually we can optimize here and remove duplicates. */
308 file_entries
->libs
[idx_old
].key
= str_offset
+ pad
;
312 /* We could subtract file_entries_new_size from str_offset -
313 not doing so makes the code easier, the string table
314 always begins at the beginning of the the new cache
316 file_entries_new
->libs
[idx_new
].flags
= entry
->flags
;
317 file_entries_new
->libs
[idx_new
].hwcap
= entry
->hwcap
;
318 file_entries_new
->libs
[idx_new
].key
= str_offset
;
320 len
= strlen (entry
->lib
);
321 str
= stpcpy (str
, entry
->lib
);
322 /* Account the final NUL. */
324 str_offset
+= len
+ 1;
327 file_entries
->libs
[idx_old
].value
= str_offset
+ pad
;
329 file_entries_new
->libs
[idx_new
].value
= str_offset
;
330 len
= strlen (entry
->path
);
331 str
= stpcpy (str
, entry
->path
);
332 /* Account the final NUL. */
334 str_offset
+= len
+ 1;
335 /* Ignore entries with hwcap for old format. */
336 if (entry
->hwcap
== 0)
340 /* Write out the cache. */
342 /* Write cache first to a temporary file and rename it later. */
343 temp_name
= xmalloc (strlen (cache_name
) + 2);
344 sprintf (temp_name
, "%s~", cache_name
);
345 /* First remove an old copy if it exists. */
346 if (unlink (temp_name
) && errno
!= ENOENT
)
347 error (EXIT_FAILURE
, errno
, _("Can't remove old temporary cache file %s"),
351 fd
= open (temp_name
, O_CREAT
|O_WRONLY
|O_TRUNC
|O_NOFOLLOW
, 0644);
353 error (EXIT_FAILURE
, errno
, _("Can't create temporary cache file %s"),
356 /* Write contents. */
359 if (write (fd
, file_entries
, file_entries_size
) != (ssize_t
)file_entries_size
)
360 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
368 if (write (fd
, zero
, pad
) != (ssize_t
)pad
)
369 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
371 if (write (fd
, file_entries_new
, file_entries_new_size
)
372 != (ssize_t
)file_entries_new_size
)
373 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed"));
376 if (write (fd
, strings
, total_strlen
) != (ssize_t
)total_strlen
)
377 error (EXIT_FAILURE
, errno
, _("Writing of cache data failed."));
381 /* Make sure user can always read cache file */
382 if (chmod (temp_name
, 0644))
383 error (EXIT_FAILURE
, errno
,
384 _("Changing access rights of %s to 0644 failed"), temp_name
);
386 /* Move temporary to its final location. */
387 if (rename (temp_name
, cache_name
))
388 error (EXIT_FAILURE
, errno
, _("Renaming of %s to %s failed"), temp_name
,
391 /* Free all allocated memory. */
400 entries
= entries
->next
;
406 /* Add one library to the cache. */
408 add_to_cache (const char *path
, const char *lib
, int flags
,
409 unsigned long int hwcap
)
411 struct cache_entry
*new_entry
, *ptr
, *prev
;
415 new_entry
= (struct cache_entry
*) xmalloc (sizeof (struct cache_entry
));
417 len
= strlen (lib
) + strlen (path
) + 2;
419 full_path
= (char *) xmalloc (len
);
420 snprintf (full_path
, len
, "%s/%s", path
, lib
);
422 new_entry
->lib
= xstrdup (lib
);
423 new_entry
->path
= full_path
;
424 new_entry
->flags
= flags
;
425 new_entry
->hwcap
= hwcap
;
426 new_entry
->bits_hwcap
= 0;
428 /* Count the number of bits set in the masked value. */
429 for (i
= 0; (~((1UL << i
) - 1) & hwcap
) != 0; ++i
)
430 if ((hwcap
& (1UL << i
)) != 0)
431 ++new_entry
->bits_hwcap
;
434 /* Keep the list sorted - search for right place to insert. */
439 if (compare (ptr
, new_entry
) > 0)
444 /* Is this the first entry? */
447 new_entry
->next
= entries
;
452 new_entry
->next
= prev
->next
;
453 prev
->next
= new_entry
;