Update.
[platform/upstream/glibc.git] / elf / cache.c
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.
4
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.
9
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.
14
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.  */
19
20 #define _GNU_SOURCE 1
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <error.h>
25 #include <dirent.h>
26 #include <libintl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/fcntl.h>
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include "ldconfig.h"
37
38 #define CACHEMAGIC "ld.so-1.7.0"
39
40 struct cache_entry
41 {
42   char *lib;
43   char *path;
44   int flags;
45   struct cache_entry *next;
46 };
47
48 struct file_entry
49 {
50   int flags;            /* This is 1 for an ELF library.  */
51   unsigned int key, value; /* String table indices.  */
52 };
53
54
55 struct cache_file
56 {
57   char magic[sizeof CACHEMAGIC - 1];
58   unsigned int nlibs;
59   struct file_entry libs[0];
60 };
61
62
63 /* List of all cache entries.  */
64 static struct cache_entry *entries;
65
66 static const char *flag_descr[] =
67 { "libc4", "ELF", "libc5", "libc6"};
68
69
70 /* Print a single entry.  */
71 static void
72 print_entry (const char *lib, int flag, const char *key)
73 {
74   printf ("\t%s (", lib);
75   switch (flag & FLAG_TYPE_MASK)
76     {
77     case FLAG_LIBC4:
78     case FLAG_ELF:
79     case FLAG_ELF_LIBC5:
80     case FLAG_ELF_LIBC6:
81       fputs (flag_descr [flag & FLAG_TYPE_MASK], stdout);
82       break;
83     default:
84       fputs ("unknown", stdout);
85       break;
86     }
87   switch (flag & FLAG_REQUIRED_MASK)
88     {
89 #ifdef __sparc__
90     case FLAG_SPARC_LIB64:
91       fputs (",64bit", stdout);
92 #endif
93     case 0:
94       break;
95     default:
96       fprintf (stdout, ",%d", flag & FLAG_REQUIRED_MASK);
97       break;
98     }
99   printf (") => %s\n", key);
100 }
101
102
103 /* Print the whole cache file.  */
104 void
105 print_cache (const char *cache_name)
106 {
107   size_t cache_size;
108   struct stat st;
109   int fd;
110   unsigned int i;
111   struct cache_file *cache;
112   const char *cache_data;
113
114   fd = open (cache_name, O_RDONLY);
115   if (fd < 0)
116     error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
117
118   if (fstat (fd, &st) < 0
119       /* No need to map the file if it is empty.  */
120       || st.st_size == 0)
121     {
122       close (fd);
123       return;
124     }
125
126   cache = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
127   if (cache == MAP_FAILED)
128     error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
129   cache_size = st.st_size;
130
131   if (cache_size < sizeof (struct cache_file)
132       || memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
133     return;
134   /* This is where the strings start.  */
135   cache_data = (const char *) &cache->libs[cache->nlibs];
136
137   printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
138
139   /* Print everything.  */
140   for (i = 0; i < cache->nlibs; i++)
141     print_entry (cache_data + cache->libs[i].key,
142                  cache->libs[i].flags,
143                  cache_data + cache->libs[i].value);
144
145   /* Cleanup.  */
146   munmap (cache, cache_size);
147   close (fd);
148 }
149
150 /* Initialize cache data structures.  */
151 void
152 init_cache (void)
153 {
154   entries = NULL;
155 }
156
157
158 /* Helper function which must match the one in the dynamic linker, so that
159    we rely on the same sort order.  */
160 int
161 cache_libcmp (const char *p1, const char *p2)
162 {
163   while (*p1 != '\0')
164     {
165       if (*p1 >= '0' && *p1 <= '9')
166         {
167           if (*p2 >= '0' && *p2 <= '9')
168             {
169               /* Must compare this numerically.  */
170               int val1;
171               int val2;
172
173               val1 = *p1++ - '0';
174               val2 = *p2++ - '0';
175               while (*p1 >= '0' && *p1 <= '9')
176                 val1 = val1 * 10 + *p1++ - '0';
177               while (*p2 >= '0' && *p2 <= '9')
178                 val2 = val2 * 10 + *p2++ - '0';
179               if (val1 != val2)
180                 return val1 - val2;
181             }
182           else
183             return 1;
184         }
185       else if (*p2 >= '0' && *p2 <= '9')
186         return -1;
187       else if (*p1 != *p2)
188         return *p1 - *p2;
189       else
190         {
191           ++p1;
192           ++p2;
193         }
194     }
195   return *p1 - *p2;
196 }
197
198 static
199 int compare (const struct cache_entry *e1, const struct cache_entry *e2)
200 {
201   int res;
202
203   /* We need to swap entries here to get the correct sort order.  */
204   res = cache_libcmp (e2->lib, e1->lib);
205   if (res == 0)
206     {
207       if (e1->flags < e2->flags)
208         return 1;
209       else if (e1->flags > e2->flags)
210         return -1;
211     }
212   return res;
213 }
214
215
216 /* Save the contents of the cache.  */
217 void
218 save_cache (const char *cache_name)
219 {
220   struct cache_entry *entry;
221   int i, fd;
222   size_t total_strlen, len;
223   char *strings, *str, *temp_name;
224   struct cache_file *file_entries;
225   size_t file_entries_size;
226   unsigned int str_offset;
227   /* Number of cache entries.  */
228   int cache_entry_count = 0;
229
230   /* The cache entries are sorted already, save them in this order. */
231
232   /* Count the length of all strings.  */
233   total_strlen = 0;
234   for (entry = entries; entry != NULL; entry = entry->next)
235     {
236       /* Account the final NULs.  */
237       total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
238       ++cache_entry_count;
239     }
240
241   /* Create the on disk cache structure.  */
242   /* First an array for all strings.  */
243   strings = (char *)xmalloc (total_strlen + 1);
244
245   /* And the list of all entries.  */
246   file_entries_size = sizeof (struct cache_file)
247     + cache_entry_count * sizeof (struct file_entry);
248   file_entries = (struct cache_file *) xmalloc (file_entries_size);
249
250   /* Fill in the header.  */
251   memset (file_entries, 0, sizeof (struct cache_file));
252   memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
253
254   file_entries->nlibs = cache_entry_count;
255
256   str_offset = 0;
257   str = strings;
258   for (i = 0, entry = entries; entry != NULL; entry = entry->next, ++i)
259     {
260       file_entries->libs[i].flags = entry->flags;
261       /* First the library.  */
262       /* XXX: Actually we can optimize here and remove duplicates.  */
263       file_entries->libs[i].key = str_offset;
264       len = strlen (entry->lib);
265       str = stpcpy (str, entry->lib);
266       /* Account the final NUL.  */
267       ++str;
268       str_offset += len + 1;
269       /* Then the path.  */
270       file_entries->libs[i].value = str_offset;
271       len = strlen (entry->path);
272       str = stpcpy (str, entry->path);
273       /* Account the final NUL.  */
274       ++str;
275       str_offset += len + 1;
276     }
277   assert (str_offset == total_strlen);
278
279   /* Write out the cache.  */
280
281   /* Write cache first to a temporary file and rename it later.  */
282   temp_name = xmalloc (strlen (cache_name) + 2);
283   sprintf (temp_name, "%s~", cache_name);
284   /* First remove an old copy if it exists.  */
285   if (unlink (temp_name) && errno != ENOENT)
286     error (EXIT_FAILURE, errno, _("Can't remove old temporary cache file %s"),
287            temp_name);
288
289   /* Create file.  */
290   fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, 0644);
291   if (fd < 0)
292     error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
293            temp_name);
294
295   /* Write contents.  */
296   if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size)
297     error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
298
299   if (write (fd, strings, total_strlen) != (ssize_t)total_strlen)
300     error (EXIT_FAILURE, errno, _("Writing of cache data failed."));
301
302   close (fd);
303
304   /* Make sure user can always read cache file */
305   if (chmod (temp_name, 0644))
306     error (EXIT_FAILURE, errno,
307            _("Changing access rights of %s to 0644 failed"), temp_name);
308
309   /* Move temporary to its final location.  */
310   if (rename (temp_name, cache_name))
311     error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
312            cache_name);
313
314   /* Free all allocated memory.  */
315   free (file_entries);
316   free (strings);
317
318   while (entries)
319     {
320       entry = entries;
321       free (entry->path);
322       free (entry->lib);
323       entries = entries->next;
324       free (entry);
325     }
326 }
327
328 /* Add one library to the cache.  */
329 void
330 add_to_cache (const char *path, const char *lib, int flags)
331 {
332   struct cache_entry *new_entry, *ptr, *prev;
333   char *full_path;
334   int len;
335
336   new_entry = (struct cache_entry *) xmalloc (sizeof (struct cache_entry));
337
338   len = strlen (lib) + strlen (path) + 2;
339
340   full_path = (char *) xmalloc (len);
341   snprintf (full_path, len, "%s/%s", path, lib);
342
343   new_entry->lib = xstrdup (lib);
344   new_entry->path = full_path;
345   new_entry->flags = flags;
346
347   /* Keep the list sorted - search for right place to insert.  */
348   ptr = entries;
349   prev = entries;
350   while (ptr != NULL)
351     {
352       if (compare (ptr, new_entry) > 0)
353         break;
354       prev = ptr;
355       ptr = ptr->next;
356     }
357   /* Is this the first entry?  */
358   if (ptr == entries)
359     {
360       new_entry->next = entries;
361       entries = new_entry;
362     }
363   else
364     {
365       new_entry->next = prev->next;
366       prev->next = new_entry;
367     }
368 }