1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #include <errno.h>
20: #include <error.h>
21: #include <dirent.h>
22: #include <inttypes.h>
23: #include <libgen.h>
24: #include <libintl.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29: #include <sys/fcntl.h>
30: #include <sys/mman.h>
31: #include <sys/stat.h>
32: #include <sys/types.h>
33:
34: #include <ldconfig.h>
35: #include <dl-cache.h>
36:
37: struct cache_entry
38: {
39: char *lib;
40: char *path;
41: int flags;
42: unsigned int osversion;
43: uint64_t hwcap;
44: int bits_hwcap;
45: struct cache_entry *next;
46: };
47:
48:
49: static struct cache_entry *entries;
50:
51: static const char *flag_descr[] =
52: { "libc4", "ELF", "libc5", "libc6"};
53:
54:
55: static void
56: print_entry (const char *lib, int flag, unsigned int osversion,
57: uint64_t hwcap, const char *key)
58: {
59: printf ("\t%s (", lib);
60: switch (flag & FLAG_TYPE_MASK)
61: {
62: case FLAG_LIBC4:
63: case FLAG_ELF:
64: case FLAG_ELF_LIBC5:
65: case FLAG_ELF_LIBC6:
66: fputs (flag_descr[flag & FLAG_TYPE_MASK], stdout);
67: break;
68: default:
69: fputs (_("unknown"), stdout);
70: break;
71: }
72: switch (flag & FLAG_REQUIRED_MASK)
73: {
74: case FLAG_SPARC_LIB64:
75: fputs (",64bit", stdout);
76: break;
77: case FLAG_IA64_LIB64:
78: fputs (",IA-64", stdout);
79: break;
80: case FLAG_X8664_LIB64:
81: fputs (",x86-64", stdout);
82: break;
83: case FLAG_S390_LIB64:
84: fputs (",64bit", stdout);
85: break;
86: case FLAG_POWERPC_LIB64:
87: fputs (",64bit", stdout);
88: break;
89: case FLAG_MIPS64_LIBN32:
90: fputs (",N32", stdout);
91: break;
92: case FLAG_MIPS64_LIBN64:
93: fputs (",64bit", stdout);
94: case 0:
95: break;
96: default:
97: printf (",%d", flag & FLAG_REQUIRED_MASK);
98: break;
99: }
100: if (hwcap != 0)
101: printf (", hwcap: %#.16" PRIx64, hwcap);
102: if (osversion != 0)
103: {
104: static const char *const abi_tag_os[] =
105: {
106: [0] = "Linux",
107: [1] = "Hurd",
108: [2] = "Solaris",
109: [3] = "FreeBSD",
110: [4] = "kNetBSD",
111: [5] = "Syllable",
112: [6] = N_("Unknown OS")
113: };
114: #define MAXTAG (sizeof abi_tag_os / sizeof abi_tag_os[0] - 1)
115: unsigned int os = osversion >> 24;
116:
117: printf (_(", OS ABI: %s %d.%d.%d"),
118: _(abi_tag_os[os > MAXTAG ? MAXTAG : os]),
119: (osversion >> 16) & 0xff,
120: (osversion >> 8) & 0xff,
121: osversion & 0xff);
122: }
123: printf (") => %s\n", key);
124: }
125:
126:
127:
128:
129: void
130: print_cache (const char *cache_name)
131: {
132: int fd = open (cache_name, O_RDONLY);
133: if (fd < 0)
134: error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
135:
136: struct stat64 st;
137: if (fstat64 (fd, &st) < 0
138:
139: || st.st_size == 0)
140: {
141: close (fd);
142: return;
143: }
144:
145: struct cache_file *cache
146: = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
147: if (cache == MAP_FAILED)
148: error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
149:
150: size_t cache_size = st.st_size;
151: if (cache_size < sizeof (struct cache_file))
152: error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
153:
154: struct cache_file_new *cache_new = NULL;
155: const char *cache_data;
156: int format = 0;
157:
158: if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
159: {
160:
161: cache_new = (struct cache_file_new *) cache;
162:
163: if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
164: || memcmp (cache_new->version, CACHE_VERSION,
165: sizeof CACHE_VERSION - 1))
166: error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
167: format = 1;
168:
169: cache_data = (const char *) cache_new;
170: }
171: else
172: {
173: size_t offset = ALIGN_CACHE (sizeof (struct cache_file)
174: + (cache->nlibs
175: * sizeof (struct file_entry)));
176:
177: cache_data = (const char *) &cache->libs[cache->nlibs];
178:
179:
180: if (cache_size >
181: (offset + sizeof (struct cache_file_new)))
182: {
183:
184: cache_new = (struct cache_file_new *) ((void *)cache + offset);
185:
186: if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
187: sizeof CACHEMAGIC_NEW - 1) == 0
188: && memcmp (cache_new->version, CACHE_VERSION,
189: sizeof CACHE_VERSION - 1) == 0)
190: {
191: cache_data = (const char *) cache_new;
192: format = 1;
193: }
194: }
195: }
196:
197: if (format == 0)
198: {
199: printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
200:
201:
202: for (unsigned int i = 0; i < cache->nlibs; i++)
203: print_entry (cache_data + cache->libs[i].key,
204: cache->libs[i].flags, 0, 0,
205: cache_data + cache->libs[i].value);
206: }
207: else if (format == 1)
208: {
209: printf (_("%d libs found in cache `%s'\n"),
210: cache_new->nlibs, cache_name);
211:
212:
213: for (unsigned int i = 0; i < cache_new->nlibs; i++)
214: print_entry (cache_data + cache_new->libs[i].key,
215: cache_new->libs[i].flags,
216: cache_new->libs[i].osversion,
217: cache_new->libs[i].hwcap,
218: cache_data + cache_new->libs[i].value);
219: }
220:
221: munmap (cache, cache_size);
222: close (fd);
223: }
224:
225:
226: void
227: init_cache (void)
228: {
229: entries = NULL;
230: }
231:
232: static int
233: compare (const struct cache_entry *e1, const struct cache_entry *e2)
234: {
235:
236: int res = _dl_cache_libcmp (e2->lib, e1->lib);
237: if (res == 0)
238: {
239: if (e1->flags < e2->flags)
240: return 1;
241: else if (e1->flags > e2->flags)
242: return -1;
243:
244: else if (e2->bits_hwcap > e1->bits_hwcap)
245: return 1;
246: else if (e2->bits_hwcap < e1->bits_hwcap)
247: return -1;
248: else if (e2->hwcap > e1->hwcap)
249: return 1;
250: else if (e2->hwcap < e1->hwcap)
251: return -1;
252: if (e2->osversion > e1->osversion)
253: return 1;
254: if (e2->osversion < e1->osversion)
255: return -1;
256: }
257: return res;
258: }
259:
260:
261: void
262: save_cache (const char *cache_name)
263: {
264:
265:
266:
267:
268:
269:
270: size_t total_strlen = 0;
271: struct cache_entry *entry;
272:
273: int cache_entry_count = 0;
274:
275: int cache_entry_old_count = 0;
276:
277: for (entry = entries; entry != NULL; entry = entry->next)
278: {
279:
280: total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
281: ++cache_entry_count;
282: if (entry->hwcap == 0)
283: ++cache_entry_old_count;
284: }
285:
286:
287: struct cache_file *file_entries = NULL;
288: size_t file_entries_size = 0;
289:
290: if (opt_format != 2)
291: {
292:
293:
294:
295:
296: if (opt_format != 0)
297: cache_entry_old_count = (cache_entry_old_count + 1) & ~1;
298:
299:
300: file_entries_size = sizeof (struct cache_file)
301: + cache_entry_old_count * sizeof (struct file_entry);
302: file_entries = xmalloc (file_entries_size);
303:
304:
305: memset (file_entries, '\0', sizeof (struct cache_file));
306: memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
307:
308: file_entries->nlibs = cache_entry_old_count;
309: }
310:
311: struct cache_file_new *file_entries_new = NULL;
312: size_t file_entries_new_size = 0;
313:
314: if (opt_format != 0)
315: {
316:
317: file_entries_new_size = sizeof (struct cache_file_new)
318: + cache_entry_count * sizeof (struct file_entry_new);
319: file_entries_new = xmalloc (file_entries_new_size);
320:
321:
322: memset (file_entries_new, '\0', sizeof (struct cache_file_new));
323: memcpy (file_entries_new->magic, CACHEMAGIC_NEW,
324: sizeof CACHEMAGIC_NEW - 1);
325: memcpy (file_entries_new->version, CACHE_VERSION,
326: sizeof CACHE_VERSION - 1);
327:
328: file_entries_new->nlibs = cache_entry_count;
329: file_entries_new->len_strings = total_strlen;
330: }
331:
332:
333: size_t pad = ALIGN_CACHE (file_entries_size) - file_entries_size;
334:
335:
336:
337:
338: unsigned int str_offset;
339: if (opt_format != 0)
340: str_offset = file_entries_new_size;
341: else
342: str_offset = 0;
343:
344:
345: char *strings = xmalloc (total_strlen);
346: char *str = strings;
347: int idx_old;
348: int idx_new;
349:
350: for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
351: entry = entry->next, ++idx_new)
352: {
353:
354: if (opt_format != 2 && entry->hwcap == 0)
355: {
356: file_entries->libs[idx_old].flags = entry->flags;
357:
358: file_entries->libs[idx_old].key = str_offset + pad;
359: }
360: if (opt_format != 0)
361: {
362:
363:
364:
365:
366: file_entries_new->libs[idx_new].flags = entry->flags;
367: file_entries_new->libs[idx_new].osversion = entry->osversion;
368: file_entries_new->libs[idx_new].hwcap = entry->hwcap;
369: file_entries_new->libs[idx_new].key = str_offset;
370: }
371:
372: size_t len = strlen (entry->lib) + 1;
373: str = mempcpy (str, entry->lib, len);
374: str_offset += len;
375:
376: if (opt_format != 2 && entry->hwcap == 0)
377: file_entries->libs[idx_old].value = str_offset + pad;
378: if (opt_format != 0)
379: file_entries_new->libs[idx_new].value = str_offset;
380: len = strlen (entry->path) + 1;
381: str = mempcpy (str, entry->path, len);
382: str_offset += len;
383:
384: if (entry->hwcap == 0)
385: ++idx_old;
386: }
387:
388:
389: if (opt_format != 2
390: && idx_old < cache_entry_old_count)
391: file_entries->libs[idx_old] = file_entries->libs[idx_old - 1];
392:
393:
394:
395:
396: char *temp_name = xmalloc (strlen (cache_name) + 2);
397: sprintf (temp_name, "%s~", cache_name);
398:
399:
400: int fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW,
401: S_IRUSR|S_IWUSR);
402: if (fd < 0)
403: error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
404: temp_name);
405:
406:
407: if (opt_format != 2)
408: {
409: if (write (fd, file_entries, file_entries_size)
410: != (ssize_t) file_entries_size)
411: error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
412: }
413: if (opt_format != 0)
414: {
415:
416: if (opt_format != 2)
417: {
418: char zero[pad];
419: memset (zero, '\0', pad);
420: if (write (fd, zero, pad) != (ssize_t) pad)
421: error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
422: }
423: if (write (fd, file_entries_new, file_entries_new_size)
424: != (ssize_t) file_entries_new_size)
425: error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
426: }
427:
428: if (write (fd, strings, total_strlen) != (ssize_t) total_strlen
429: || close (fd))
430: error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
431:
432:
433: if (chmod (temp_name, S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR))
434: error (EXIT_FAILURE, errno,
435: _("Changing access rights of %s to %#o failed"), temp_name,
436: S_IROTH|S_IRGRP|S_IRUSR|S_IWUSR);
437:
438:
439: if (rename (temp_name, cache_name))
440: error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
441: cache_name);
442:
443:
444: free (file_entries_new);
445: free (file_entries);
446: free (strings);
447:
448: while (entries)
449: {
450: entry = entries;
451: entries = entries->next;
452: free (entry);
453: }
454: }
455:
456:
457:
458: void
459: add_to_cache (const char *path, const char *lib, int flags,
460: unsigned int osversion, uint64_t hwcap)
461: {
462: size_t liblen = strlen (lib) + 1;
463: size_t len = liblen + strlen (path) + 1;
464: struct cache_entry *new_entry
465: = xmalloc (sizeof (struct cache_entry) + liblen + len);
466:
467: new_entry->lib = memcpy ((char *) (new_entry + 1), lib, liblen);
468: new_entry->path = new_entry->lib + liblen;
469: snprintf (new_entry->path, len, "%s/%s", path, lib);
470: new_entry->flags = flags;
471: new_entry->osversion = osversion;
472: new_entry->hwcap = hwcap;
473: new_entry->bits_hwcap = 0;
474:
475:
476: for (size_t i = 0;
477: (~((1ULL << i) - 1) & hwcap) != 0 && i < 8 * sizeof (hwcap); ++i)
478: if ((hwcap & (1ULL << i)) != 0)
479: ++new_entry->bits_hwcap;
480:
481:
482:
483: struct cache_entry *ptr = entries;
484: struct cache_entry *prev = entries;
485: while (ptr != NULL)
486: {
487: if (compare (ptr, new_entry) > 0)
488: break;
489: prev = ptr;
490: ptr = ptr->next;
491: }
492:
493: if (ptr == entries)
494: {
495: new_entry->next = entries;
496: entries = new_entry;
497: }
498: else
499: {
500: new_entry->next = prev->next;
501: prev->next = new_entry;
502: }
503: }
504:
505:
506:
507:
508: struct aux_cache_entry_id
509: {
510: uint64_t ino;
511: uint64_t ctime;
512: uint64_t size;
513: uint64_t dev;
514: };
515:
516: struct aux_cache_entry
517: {
518: struct aux_cache_entry_id id;
519: int flags;
520: unsigned int osversion;
521: int used;
522: char *soname;
523: struct aux_cache_entry *next;
524: };
525:
526: #define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
527:
528: struct aux_cache_file_entry
529: {
530: struct aux_cache_entry_id id;
531: int32_t flags;
532: uint32_t soname;
533: uint32_t osversion;
534: int32_t pad;
535: };
536:
537:
538:
539:
540:
541: struct aux_cache_file
542: {
543: char magic[sizeof AUX_CACHEMAGIC - 1];
544: uint32_t nlibs;
545: uint32_t len_strings;
546: struct aux_cache_file_entry libs[0];
547:
548: };
549:
550: static const unsigned int primes[] =
551: {
552: 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
553: 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393,
554: 67108859, 134217689, 268435399, 536870909, 1073741789, 2147483647
555: };
556:
557: static size_t aux_hash_size;
558: static struct aux_cache_entry **aux_hash;
559:
560:
561: static unsigned int
562: aux_cache_entry_id_hash (struct aux_cache_entry_id *id)
563: {
564: uint64_t ret = ((id->ino * 11 + id->ctime) * 11 + id->size) * 11 + id->dev;
565: return ret ^ (ret >> 32);
566: }
567:
568: static size_t nextprime (size_t x)
569: {
570: for (unsigned int i = 0; i < sizeof (primes) / sizeof (primes[0]); ++i)
571: if (primes[i] >= x)
572: