1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19: #define PROCINFO_CLASS static
20: #include <alloca.h>
21: #include <argp.h>
22: #include <dirent.h>
23: #include <elf.h>
24: #include <error.h>
25: #include <errno.h>
26: #include <inttypes.h>
27: #include <libintl.h>
28: #include <locale.h>
29: #include <stdbool.h>
30: #include <stdio.h>
31: #include <stdio_ext.h>
32: #include <stdlib.h>
33: #include <string.h>
34: #include <unistd.h>
35: #include <sys/fcntl.h>
36: #include <sys/mman.h>
37: #include <sys/stat.h>
38: #include <sys/types.h>
39: #include <glob.h>
40: #include <libgen.h>
41:
42: #include <ldconfig.h>
43: #include <dl-cache.h>
44:
45: #include <dl-procinfo.h>
46:
47: #ifdef _DL_FIRST_PLATFORM
48: # define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
49: #else
50: # define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
51: #endif
52:
53: #ifndef LD_SO_CONF
54: # define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
55: #endif
56:
57:
58: #include <version.h>
59:
60: #define PACKAGE _libc_intl_domainname
61:
62: static const struct
63: {
64: const char *name;
65: int flag;
66: } lib_types[] =
67: {
68: {"libc4", FLAG_LIBC4},
69: {"libc5", FLAG_ELF_LIBC5},
70: {"libc6", FLAG_ELF_LIBC6},
71: {"glibc2", FLAG_ELF_LIBC6}
72: };
73:
74:
75:
76: struct dir_entry
77: {
78: char *path;
79: int flag;
80: ino64_t ino;
81: dev_t dev;
82: struct dir_entry *next;
83: };
84:
85:
86:
87: static struct dir_entry *dir_entries;
88:
89:
90:
91: static int opt_print_cache;
92:
93:
94: int opt_verbose;
95:
96:
97:
98: int opt_format = 1;
99:
100:
101: static int opt_build_cache = 1;
102:
103:
104: static int opt_link = 1;
105:
106:
107: static int opt_only_cline;
108:
109:
110: static char *opt_chroot;
111:
112:
113: static int opt_manual_link;
114:
115:
116: static int opt_ignore_aux_cache;
117:
118:
119: static char *cache_file;
120:
121:
122: static const char *config_file;
123:
124:
125: static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
126:
127:
128: static const char *hwcap_extra[64 - _DL_FIRST_EXTRA];
129:
130:
131: static void print_version (FILE *stream, struct argp_state *state);
132: void (*argp_program_version_hook) (FILE *, struct argp_state *)
133: = print_version;
134:
135:
136: static const struct argp_option options[] =
137: {
138: { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
139: { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
140: { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
141: { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
142: { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
143: { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
144: { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
145: { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
146: { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
147: { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0},
148: { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
149: { NULL, 0, NULL, 0, NULL, 0 }
150: };
151:
152: #define PROCINFO_CLASS static
153: #include <dl-procinfo.c>
154:
155:
156: static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
157:
158:
159: static error_t parse_opt (int key, char *arg, struct argp_state *state);
160:
161:
162: static struct argp argp =
163: {
164: options, parse_opt, NULL, doc, NULL, NULL, NULL
165: };
166:
167:
168:
169: static int
170: is_hwcap_platform (const char *name)
171: {
172: int hwcap_idx = _dl_string_hwcap (name);
173:
174: if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
175: return 1;
176:
177: hwcap_idx = _dl_string_platform (name);
178: if (hwcap_idx != -1)
179: return 1;
180:
181: for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
182: if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
183: && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
184: return 1;
185:
186: return 0;
187: }
188:
189:
190: static uint64_t
191: path_hwcap (const char *path)
192: {
193: char *str = xstrdup (path);
194: char *ptr;
195: uint64_t hwcap = 0;
196: uint64_t h;
197:
198: size_t len;
199:
200: len = strlen (str);
201: if (str[len] == '/')
202: str[len] = '\0';
203:
204:
205: for (;;)
206: {
207: ptr = strrchr (str, '/');
208:
209: if (ptr == NULL)
210: break;
211:
212: h = _dl_string_hwcap (ptr + 1);
213:
214: if (h == (uint64_t) -1)
215: {
216: h = _dl_string_platform (ptr + 1);
217: if (h == (uint64_t) -1)
218: {
219: for (h = _DL_FIRST_EXTRA; h < 64; ++h)
220: if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
221: && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
222: break;
223: if (h == 64)
224: break;
225: }
226: }
227: hwcap += 1ULL << h;
228:
229:
230: *ptr = '\0';
231: }
232:
233: free (str);
234: return hwcap;
235: }
236:
237:
238: static error_t
239: parse_opt (int key, char *arg, struct argp_state *state)
240: {
241: switch (key)
242: {
243: case 'C':
244: cache_file = arg;
245:
246: opt_ignore_aux_cache = 1;
247: break;
248: case 'f':
249: config_file = arg;
250: break;
251: case 'i':
252: opt_ignore_aux_cache = 1;
253: break;
254: case 'l':
255: opt_manual_link = 1;
256: break;
257: case 'N':
258: opt_build_cache = 0;
259: break;
260: case 'n':
261: opt_build_cache = 0;
262: opt_only_cline = 1;
263: break;
264: case 'p':
265: opt_print_cache = 1;
266: break;
267: case 'r':
268: opt_chroot = arg;
269: break;
270: case 'v':
271: opt_verbose = 1;
272: break;
273: case 'X':
274: opt_link = 0;
275: break;
276: case 'c':
277: if (strcmp (arg, "old") == 0)
278: opt_format = 0;
279: else if (strcmp (arg, "compat") == 0)
280: opt_format = 1;
281: else if (strcmp (arg, "new") == 0)
282: opt_format = 2;
283: break;
284: default:
285: return ARGP_ERR_UNKNOWN;
286: }
287:
288: return 0;
289: }
290:
291:
292: static void
293: print_version (FILE *stream, struct argp_state *state)
294: {
295: fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
296: fprintf (stream, gettext ("\
297: Copyright (C) %s Free Software Foundation, Inc.\n\
298: This is free software; see the source for copying conditions. There is NO\n\
299: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
300: "), "2007");
301: fprintf (stream, gettext ("Written by %s.\n"),
302: "Andreas Jaeger");
303: }
304:
305:
306: static void
307: add_single_dir (struct dir_entry *entry, int verbose)
308: {
309: struct dir_entry *ptr, *prev;
310:
311: ptr = dir_entries;
312: prev = ptr;
313: while (ptr != NULL)
314: {
315:
316: if (ptr->ino == entry->ino && ptr->dev == entry->dev)
317: {
318: if (opt_verbose && verbose)
319: error (0, 0, _("Path `%s' given more than once"), entry->path);
320:
321: ptr->flag = entry->flag;
322: free (entry->path);
323: free (entry);
324: break;
325: }
326: prev = ptr;
327: ptr = ptr->next;
328: }
329:
330: if (ptr == NULL && dir_entries == NULL)
331: dir_entries = entry;
332: else if (ptr == NULL)
333: prev->next = entry;
334: }
335:
336:
337: static void
338: add_dir (const char *line)
339: {
340: unsigned int i;
341: struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
342: entry->next = NULL;
343:
344:
345: entry->path = xstrdup (line);
346: char *equal_sign = strchr (entry->path, '=');
347: if (equal_sign)
348: {
349: *equal_sign = '\0';
350: ++equal_sign;
351: entry->flag = FLAG_ANY;
352: for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
353: if (strcmp (equal_sign, lib_types[i].name) == 0)
354: {
355: entry->flag = lib_types[i].flag;
356: break;
357: }
358: if (entry->flag == FLAG_ANY)
359: error (0, 0, _("%s is not a known library type"), equal_sign);
360: }
361: else
362: {
363: entry->flag = FLAG_ANY;
364: }
365:
366:
367:
368: i = strlen (entry->path) - 1;
369:
370: while (isspace (entry->path[i]) && i > 0)
371: entry->path[i--] = '\0';
372:
373: while (entry->path[i] == '/' && i > 0)
374: entry->path[i--] = '\0';
375:
376: char *path = entry->path;
377: if (opt_chroot)
378: path = chroot_canon (opt_chroot, path);
379:
380: struct stat64 stat_buf;
381: if (path == NULL || stat64 (path, &stat_buf))
382: {
383: if (opt_verbose)
384: error (0, errno, _("Can't stat %s"), entry->path);
385: free (entry->path);
386: free (entry);
387: }
388: else
389: {
390: entry->ino = stat_buf.st_ino;
391: entry->dev = stat_buf.st_dev;
392:
393: add_single_dir (entry, 1);
394: }
395:
396: if (opt_chroot)
397: free (path);
398: }
399:
400:
401: static int
402: chroot_stat (const char *real_path, const char *path, struct stat64 *st)
403: {
404: int ret;
405: char *canon_path;
406:
407: if (!opt_chroot)
408: return stat64 (real_path, st);
409:
410: ret = lstat64 (real_path, st);
411: if (ret || !S_ISLNK (st->st_mode))
412: return ret;
413:
414: canon_path = chroot_canon (opt_chroot, path);
415: if (canon_path == NULL)
416: return -1;
417:
418: ret = stat64 (canon_path, st);
419: free (canon_path);
420: return ret;
421: }
422:
423:
424: static void
425: create_links (const char *real_path, const char *path, const char *libname,
426: const char *soname)
427: {
428: char *full_libname, *full_soname;
429: char *real_full_libname, *real_full_soname;
430: struct stat64 stat_lib, stat_so, lstat_so;
431: int do_link = 1;
432: int do_remove = 1;
433:
434:
435:
436: full_libname = alloca (strlen (path) + strlen (libname) + 2);
437: full_soname = alloca (strlen (path) + strlen (soname) + 2);
438: sprintf (full_libname, "%s/%s", path, libname);
439: sprintf (full_soname, "%s/%s", path, soname);
440: if (opt_chroot)
441: {
442: real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
443: real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
444: sprintf (real_full_libname, "%s/%s", real_path, libname);
445: sprintf (real_full_soname, "%s/%s", real_path, soname);
446: }
447: else
448: {
449: real_full_libname = full_libname;
450: real_full_soname = full_soname;
451: }
452:
453:
454: if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
455: {
456: if (chroot_stat (real_full_libname, full_libname, &stat_lib))
457: {
458: error (0, 0, _("Can't stat %s\n"), full_libname);
459: return;
460: }
461: if (stat_lib.st_dev == stat_so.st_dev
462: && stat_lib.st_ino == stat_so.st_ino)
463:
464: do_link = 0;
465: else if (lstat64 (full_soname, &lstat_so) == 0
466: && !S_ISLNK (lstat_so.st_mode))
467: {
468: error (0, 0, _("%s is not a symbolic link\n"), full_soname);
469: do_link = 0;
470: do_remove = 0;
471: }
472: }
473: else if (lstat64 (real_full_soname, &lstat_so) != 0
474: || !S_ISLNK (lstat_so.st_mode))
475:
476: do_remove = 0;
477:
478: if (opt_verbose)
479: printf ("\t%s -> %s", soname, libname);
480:
481: if (do_link && opt_link)
482: {
483:
484: if (do_remove)
485: if (unlink (real_full_soname))
486: {
487: error (0, 0, _("Can't unlink %s"), full_soname);
488: do_link = 0;
489: }
490:
491: if (do_link && symlink (libname, real_full_soname))
492: {
493: error (0, 0, _("Can't link %s to %s"), full_soname, libname);
494: do_link = 0;
495: }
496: if (opt_verbose)
497: {
498: if (do_link)
499: fputs (_(" (changed)\n"), stdout);
500: else
501: fputs (_(" (SKIPPED)\n"), stdout);
502: }
503: }
504: else if (opt_verbose)
505: fputs ("\n", stdout);
506: }
507:
508:
509: static void
510: manual_link (char *library)
511: {
512: char *path;
513: char *real_path;
514: char *real_library;
515: char *libname;
516: char *soname;
517: struct stat64 stat_buf;
518: int flag;
519: unsigned int osversion;
520:
521:
522:
523:
524: path = xstrdup (library);
525: libname = strrchr (path, '/');
526:
527: if (libname)
528: {
529:
530:
531: if (libname == path)
532: {
533: libname = library + 1;
534: path = xrealloc (path, 2);
535: strcpy (path, "/");
536: }
537: else
538: {
539: *libname = '\0';
540: ++libname;
541: }
542: }
543: else
544: {
545:
546: libname = library;
547: path = xrealloc (path, 2);
548: strcpy (path, ".");
549: }
550:
551: if (opt_chroot)
552: {
553: real_path = chroot_canon (opt_chroot, path);
554: if (real_path == NULL)
555: {
556: error (0, errno, _("Can't find %s"), path);
557: free (path);
558: return;
559: }
560: real_library = alloca (strlen (real_path) + strlen (libname) + 2);
561: sprintf (real_library, "%s/%s", real_path, libname);
562: }
563: else
564: {
565: real_path = path;
566: real_library = library;
567: }
568:
569:
570: if (lstat64 (real_library, &stat_buf))
571: {
572: error (0, errno, _("Cannot lstat %s"), library);
573: free (path);
574: return;
575: }
576:
577: else if (!S_ISREG (stat_buf.st_mode))
578: {
579: error (0, 0, _("Ignored file %s since it is not a regular file."),
580: library);
581: free (path);
582: return;
583: }
584:
585: if (process_file (real_library, library, libname, &flag, &osversion,
586: &soname, 0, &stat_buf))
587: {
588: error (0, 0, _("No link created since soname could not be found for %s"),
589: