]> git.ipfire.org Git - thirdparty/glibc.git/blob - elf/ldconfig.c
Update.
[thirdparty/glibc.git] / elf / ldconfig.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 #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 <libintl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <stdint.h>
32 #include <sys/fcntl.h>
33 #include <sys/mman.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include "ldconfig.h"
38 #include "dl-cache.h"
39
40 /* We don't need this here - silence the compiler. */
41 #define _dl_sysdep_message(string, args...) do {} while (0);
42
43 #include "dl-procinfo.h"
44
45 #ifndef LD_SO_CONF
46 # define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
47 #endif
48
49 /* Get libc version number. */
50 #include <version.h>
51
52 #define PACKAGE _libc_intl_domainname
53
54 struct lib_entry
55 {
56 int flags;
57 uint64_t hwcap;
58 char *lib;
59 char *path;
60 };
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 /* List of directories to handle. */
76 struct dir_entry
77 {
78 char *path;
79 int flag;
80 struct dir_entry *next;
81 };
82
83 /* The list is unsorted, contains no duplicates. Entries are added at
84 the end. */
85 static struct dir_entry *dir_entries;
86
87 /* Flags for different options. */
88 /* Print Cache. */
89 static int opt_print_cache = 0;
90
91 /* Be verbose. */
92 int opt_verbose = 0;
93
94 /* Format to support. */
95 /* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
96 int opt_format = 1;
97
98 /* Build cache. */
99 static int opt_build_cache = 1;
100
101 /* Generate links. */
102 static int opt_link = 1;
103
104 /* Only process directories specified on the command line. */
105 static int opt_only_cline = 0;
106
107 /* Path to root for chroot. */
108 static char *opt_chroot;
109
110 /* Manually link given shared libraries. */
111 static int opt_manual_link = 0;
112
113 /* Cache file to use. */
114 static char *cache_file;
115
116 /* Configuration file. */
117 static const char *config_file;
118
119 /* Name and version of program. */
120 static void print_version (FILE *stream, struct argp_state *state);
121 void (*argp_program_version_hook) (FILE *, struct argp_state *)
122 = print_version;
123
124 /* Definitions of arguments for argp functions. */
125 static const struct argp_option options[] =
126 {
127 { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
128 { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
129 { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
130 { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
131 { NULL, 'r', "ROOT", 0, N_("Change to and use ROOT as root directory"), 0},
132 { NULL, 'C', "CACHE", 0, N_("Use CACHE as cache file"), 0},
133 { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 0},
134 { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
135 { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
136 { "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0},
137 { NULL, 0, NULL, 0, NULL, 0 }
138 };
139
140 /* Short description of program. */
141 static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
142
143 /* Prototype for option handler. */
144 static error_t parse_opt (int key, char *arg, struct argp_state *state);
145
146 /* Data structure to communicate with argp functions. */
147 static struct argp argp =
148 {
149 options, parse_opt, NULL, doc, NULL, NULL, NULL
150 };
151
152 /* Check if string corresponds to an important hardware capability or
153 a platform. */
154 static int
155 is_hwcap_platform (const char *name)
156 {
157 int hwcap_idx = _dl_string_hwcap (name);
158
159 if (hwcap_idx != -1 && ((1 << hwcap_idx) & HWCAP_IMPORTANT))
160 return 1;
161
162 hwcap_idx = _dl_string_platform (name);
163 if (hwcap_idx != -1)
164 return 1;
165
166 return 0;
167 }
168
169 /* Get hwcap (including platform) encoding of path. */
170 static uint64_t
171 path_hwcap (const char *path)
172 {
173 char *str = xstrdup (path);
174 char *ptr;
175 uint64_t hwcap = 0;
176 uint64_t h;
177
178 size_t len;
179
180 len = strlen (str);
181 if (str[len] == '/')
182 str[len] = '\0';
183
184 /* Search pathname from the end and check for hwcap strings. */
185 for (;;)
186 {
187 ptr = strrchr (str, '/');
188
189 if (ptr == NULL)
190 break;
191
192 h = _dl_string_hwcap (ptr + 1);
193
194 if (h == (uint64_t) -1)
195 {
196 h = _dl_string_platform (ptr + 1);
197 if (h == (uint64_t) -1)
198 break;
199 }
200 hwcap += 1ULL << h;
201
202 /* Search the next part of the path. */
203 *ptr = '\0';
204 }
205
206 free (str);
207 return hwcap;
208 }
209
210 /* Handle program arguments. */
211 static error_t
212 parse_opt (int key, char *arg, struct argp_state *state)
213 {
214 switch (key)
215 {
216 case 'C':
217 cache_file = arg;
218 break;
219 case 'f':
220 config_file = arg;
221 break;
222 case 'l':
223 opt_manual_link = 1;
224 break;
225 case 'N':
226 opt_build_cache = 0;
227 break;
228 case 'n':
229 opt_build_cache = 0;
230 opt_only_cline = 1;
231 break;
232 case 'p':
233 opt_print_cache = 1;
234 break;
235 case 'r':
236 opt_chroot = arg;
237 break;
238 case 'v':
239 opt_verbose = 1;
240 break;
241 case 'X':
242 opt_link = 0;
243 break;
244 case 'c':
245 if (strcmp (arg, "old") == 0)
246 opt_format = 0;
247 else if (strcmp (arg, "compat") == 0)
248 opt_format = 1;
249 else if (strcmp (arg, "new") == 0)
250 opt_format = 2;
251 break;
252 default:
253 return ARGP_ERR_UNKNOWN;
254 }
255
256 return 0;
257 }
258
259 /* Print the version information. */
260 static void
261 print_version (FILE *stream, struct argp_state *state)
262 {
263 fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
264 fprintf (stream, gettext ("\
265 Copyright (C) %s Free Software Foundation, Inc.\n\
266 This is free software; see the source for copying conditions. There is NO\n\
267 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
268 "), "2000");
269 fprintf (stream, gettext ("Written by %s.\n"),
270 "Andreas Jaeger");
271 }
272
273 /* Add a single directory entry. */
274 static void
275 add_single_dir (struct dir_entry *entry, int verbose)
276 {
277 struct dir_entry *ptr, *prev;
278
279 ptr = dir_entries;
280 prev = ptr;
281 while (ptr != NULL)
282 {
283 /* Check for duplicates. */
284 if (strcmp (ptr->path, entry->path) == 0)
285 {
286 if (opt_verbose && verbose)
287 error (0, 0, _("Path `%s' given more than once"), entry->path);
288 /* Use the newer information. */
289 ptr->flag = entry->flag;
290 free (entry);
291 break;
292 }
293 prev = ptr;
294 ptr = ptr->next;
295 }
296 /* Is this the first entry? */
297 if (ptr == NULL && dir_entries == NULL)
298 dir_entries = entry;
299 else if (ptr == NULL)
300 prev->next = entry;
301 }
302
303 /* Add one directory to the list of directories to process. */
304 static void
305 add_dir (const char *line)
306 {
307 char *equal_sign;
308 struct dir_entry *entry;
309 unsigned int i;
310
311 entry = xmalloc (sizeof (struct dir_entry));
312 entry->next = NULL;
313
314 /* Search for an '=' sign. */
315 entry->path = xstrdup (line);
316 equal_sign = strchr (entry->path, '=');
317 if (equal_sign)
318 {
319 *equal_sign = '\0';
320 ++equal_sign;
321 entry->flag = FLAG_ANY;
322 for (i = 0; i < sizeof (lib_types) / sizeof (lib_types [0]); ++i)
323 if (strcmp (equal_sign, lib_types[i].name) == 0)
324 {
325 entry->flag = lib_types[i].flag;
326 break;
327 }
328 if (entry->flag == FLAG_ANY)
329 error (0, 0, _("%s is not a known library type"), equal_sign);
330 }
331 else
332 {
333 entry->flag = FLAG_ANY;
334 }
335
336 /* Canonify path: for now only remove trailing slashes. */
337 i = strlen (entry->path) - 1;
338 while (entry->path[i] == '/' && i > 0)
339 {
340 entry->path [i] = '\0';
341 --i;
342 }
343
344 add_single_dir (entry, 1);
345 }
346
347
348 static int
349 chroot_stat (const char *real_path, const char *path, struct stat64 *st)
350 {
351 int ret;
352 char *canon_path;
353
354 if (!opt_chroot)
355 return stat64 (real_path, st);
356
357 ret = lstat64 (real_path, st);
358 if (ret || !S_ISLNK (st->st_mode))
359 return ret;
360
361 canon_path = chroot_canon (opt_chroot, path);
362 if (canon_path == NULL)
363 return -1;
364
365 ret = stat64 (canon_path, st);
366 free (canon_path);
367 return ret;
368 }
369
370 /* Create a symbolic link from soname to libname in directory path. */
371 static void
372 create_links (const char *real_path, const char *path, const char *libname,
373 const char *soname)
374 {
375 char *full_libname, *full_soname;
376 char *real_full_libname, *real_full_soname;
377 struct stat64 stat_lib, stat_so, lstat_so;
378 int do_link = 1;
379 int do_remove = 1;
380 /* XXX: The logics in this function should be simplified. */
381
382 /* Get complete path. */
383 full_libname = alloca (strlen (path) + strlen (libname) + 2);
384 full_soname = alloca (strlen (path) + strlen (soname) + 2);
385 sprintf (full_libname, "%s/%s", path, libname);
386 sprintf (full_soname, "%s/%s", path, soname);
387 if (opt_chroot)
388 {
389 real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
390 real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
391 sprintf (real_full_libname, "%s/%s", real_path, libname);
392 sprintf (real_full_soname, "%s/%s", real_path, soname);
393 }
394 else
395 {
396 real_full_libname = full_libname;
397 real_full_soname = full_soname;
398 }
399
400 /* Does soname already exist and point to the right library? */
401 if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
402 {
403 if (chroot_stat (real_full_libname, full_libname, &stat_lib))
404 {
405 error (0, 0, _("Can't stat %s\n"), full_libname);
406 return;
407 }
408 if (stat_lib.st_dev == stat_so.st_dev
409 && stat_lib.st_ino == stat_so.st_ino)
410 /* Link is already correct. */
411 do_link = 0;
412 else if (lstat64 (full_soname, &lstat_so) == 0
413 && !S_ISLNK (lstat_so.st_mode))
414 {
415 error (0, 0, _("%s is not a symbolic link\n"), full_soname);
416 do_link = 0;
417 do_remove = 0;
418 }
419 }
420 else if (lstat64 (real_full_soname, &lstat_so) != 0
421 || !S_ISLNK (lstat_so.st_mode))
422 /* Unless it is a stale symlink, there is no need to remove. */
423 do_remove = 0;
424
425 if (opt_verbose)
426 printf ("\t%s -> %s", soname, libname);
427
428 if (do_link && opt_link)
429 {
430 /* Remove old link. */
431 if (do_remove)
432 if (unlink (real_full_soname))
433 {
434 error (0, 0, _("Can't unlink %s"), full_soname);
435 do_link = 0;
436 }
437 /* Create symbolic link. */
438 if (do_link && symlink (libname, real_full_soname))
439 {
440 error (0, 0, _("Can't link %s to %s"), full_soname, libname);
441 do_link = 0;
442 }
443 if (opt_verbose)
444 {
445 if (do_link)
446 fputs (_(" (changed)\n"), stdout);
447 else
448 fputs (_(" (SKIPPED)\n"), stdout);
449 }
450 }
451 else if (opt_verbose)
452 fputs ("\n", stdout);
453 }
454
455 /* Manually link the given library. */
456 static void
457 manual_link (char *library)
458 {
459 char *path;
460 char *real_path;
461 char *real_library;
462 char *libname;
463 char *soname;
464 struct stat64 stat_buf;
465 int flag;
466
467 /* Prepare arguments for create_links call. Split library name in
468 directory and filename first. Since path is allocated, we've got
469 to be careful to free at the end. */
470 path = xstrdup (library);
471 libname = strrchr (path, '/');
472
473 if (libname)
474 {
475 /* Successfully split names. Check if path is just "/" to avoid
476 an empty path. */
477 if (libname == path)
478 {
479 libname = library + 1;
480 path = xrealloc (path, 2);
481 strcpy (path, "/");
482 }
483 else
484 {
485 *libname = '\0';
486 ++libname;
487 }
488 }
489 else
490 {
491 /* There's no path, construct one. */
492 libname = library;
493 path = xrealloc (path, 2);
494 strcpy (path, ".");
495 }
496
497 if (opt_chroot)
498 {
499 real_path = chroot_canon (opt_chroot, path);
500 if (real_path == NULL)
501 {
502 error (0, errno, _("Can't find %s"), path);
503 free (path);
504 return;
505 }
506 real_library = alloca (strlen (real_path) + strlen (libname) + 2);
507 sprintf (real_library, "%s/%s", real_path, libname);
508 }
509 else
510 {
511 real_path = path;
512 real_library = library;
513 }
514
515 /* Do some sanity checks first. */
516 if (lstat64 (real_library, &stat_buf))
517 {
518 error (0, errno, _("Can't lstat %s"), library);
519 free (path);
520 return;
521 }
522 /* We don't want links here! */
523 else if (!S_ISREG (stat_buf.st_mode))
524 {
525 error (0, 0, _("Ignored file %s since it is not a regular file."),
526 library);
527 free (path);
528 return;
529 }
530 if (process_file (real_library, library, libname, &flag, &soname, 0))
531 {
532 error (0, 0, _("No link created since soname could not be found for %s"),
533 library);
534 free (path);
535 return;
536 }
537 create_links (real_path, path, libname, soname);
538 free (soname);
539 free (path);
540 }
541
542
543 /* Read a whole directory and search for libraries.
544 The purpose is two-fold:
545 - search for libraries which will be added to the cache
546 - create symbolic links to the soname for each library
547
548 This has to be done separatly for each directory.
549
550 To keep track of which libraries to add to the cache and which
551 links to create, we save a list of all libraries.
552
553 The algorithm is basically:
554 for all libraries in the directory do
555 get soname of library
556 if soname is already in list
557 if new library is newer, replace entry
558 otherwise ignore this library
559 otherwise add library to list
560
561 For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
562 exist and both have the same soname, e.g. libxy.so, a symbolic link
563 is created from libxy.so.1.2 (the newer one) to libxy.so.
564 libxy.so.1.2 and libxy.so are added to the cache - but not
565 libxy.so.1.1. */
566
567 /* Information for one library. */
568 struct dlib_entry
569 {
570 char *name;
571 char *soname;
572 int flag;
573 int is_link;
574 struct dlib_entry *next;
575 };
576
577
578 static void
579 search_dir (const struct dir_entry *entry)
580 {
581 DIR *dir;
582 struct dirent *direntry;
583 char *file_name, *dir_name, *real_file_name, *real_name;
584 int file_name_len, real_file_name_len, len;
585 char *soname;
586 struct dlib_entry *dlibs;
587 struct dlib_entry *dlib_ptr;
588 struct stat64 stat_buf;
589 int is_link;
590 uint64_t hwcap = path_hwcap (entry->path);
591
592 file_name_len = PATH_MAX;
593 file_name = alloca (file_name_len);
594
595 dlibs = NULL;
596
597 if (opt_verbose)
598 {
599 if (hwcap != 0)
600 printf ("%s: (hwcap: 0x%Lx)\n", entry->path, hwcap);
601 else
602 printf ("%s:\n", entry->path);
603 }
604
605 if (opt_chroot)
606 {
607 dir_name = chroot_canon (opt_chroot, entry->path);
608 real_file_name_len = PATH_MAX;
609 real_file_name = alloca (real_file_name_len);
610 }
611 else
612 {
613 dir_name = entry->path;
614 real_file_name_len = 0;
615 real_file_name = file_name;
616 }
617
618 if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
619 {
620 if (opt_verbose)
621 error (0, errno, _("Can't open directory %s"), entry->path);
622 if (opt_chroot && dir_name)
623 free (dir_name);
624 return;
625 }
626
627 while ((direntry = readdir (dir)) != NULL)
628 {
629 int flag;
630 #ifdef _DIRENT_HAVE_D_TYPE
631 /* We only look at links and regular files. */
632 if (direntry->d_type != DT_UNKNOWN
633 && direntry->d_type != DT_LNK
634 && direntry->d_type != DT_REG
635 && direntry->d_type != DT_DIR)
636 continue;
637 #endif /* _DIRENT_HAVE_D_TYPE */
638 /* Does this file look like a shared library or is it a hwcap
639 subdirectory? The dynamic linker is also considered as
640 shared library. */
641 if (((strncmp (direntry->d_name, "lib", 3) != 0
642 && strncmp (direntry->d_name, "ld-", 3) != 0)
643 || strstr (direntry->d_name, ".so") == NULL)
644 && !is_hwcap_platform (direntry->d_name))
645 continue;
646 len = strlen (entry->path) + strlen (direntry->d_name);
647 if (len > file_name_len)
648 {
649 file_name_len = len + 1;
650 file_name = alloca (file_name_len);
651 if (!opt_chroot)
652 real_file_name = file_name;
653 }
654 sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
655 if (opt_chroot)
656 {
657 len = strlen (dir_name) + strlen (direntry->d_name);
658 if (len > real_file_name_len)
659 {
660 real_file_name_len = len + 1;
661 real_file_name = alloca (real_file_name_len);
662 }
663 sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
664 }
665 #ifdef _DIRENT_HAVE_D_TYPE
666 if (direntry->d_type != DT_UNKNOWN)
667 stat_buf.st_mode = DTTOIF (direntry->d_type);
668 else
669 #endif
670 if (lstat64 (real_file_name, &stat_buf))
671 {
672 error (0, errno, _("Can't lstat %s"), file_name);
673 continue;
674 }
675
676 if (S_ISDIR (stat_buf.st_mode) && is_hwcap_platform (direntry->d_name))
677 {
678 /* Handle subdirectory later. */
679 struct dir_entry *new_entry;
680
681 new_entry = xmalloc (sizeof (struct dir_entry));
682 new_entry->path = xstrdup (file_name);
683 new_entry->flag = entry->flag;
684 new_entry->next = NULL;
685 add_single_dir (new_entry, 0);
686 continue;
687 }
688 else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode))
689 continue;
690
691 is_link = S_ISLNK (stat_buf.st_mode);
692 if (opt_chroot && is_link)
693 {
694 real_name = chroot_canon (opt_chroot, file_name);
695 if (real_name == NULL)
696 {
697 if (strstr (file_name, ".so") == NULL)
698 error (0, 0, _("Input file %s not found.\n"), file_name);
699 continue;
700 }
701 }
702 else
703 real_name = real_file_name;
704
705 if (process_file (real_name, file_name, direntry->d_name, &flag,
706 &soname, is_link))
707 {
708 if (real_name != real_file_name)
709 free (real_name);
710 continue;
711 }
712
713 if (real_name != real_file_name)
714 free (real_name);
715
716 /* Links will just point to itself. */
717 if (is_link)
718 {
719 free (soname);
720 soname = xstrdup (direntry->d_name);
721 }
722
723 if (flag == FLAG_ELF
724 && (entry->flag == FLAG_ELF_LIBC5
725 || entry->flag == FLAG_ELF_LIBC6))
726 flag = entry->flag;
727 /* Some sanity checks to print warnings. */
728 if (opt_verbose)
729 {
730 if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
731 && entry->flag != FLAG_ANY)
732 error (0, 0, _("libc5 library %s in wrong directory"), file_name);
733 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
734 && entry->flag != FLAG_ANY)
735 error (0, 0, _("libc6 library %s in wrong directory"), file_name);
736 if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
737 && entry->flag != FLAG_ANY)
738 error (0, 0, _("libc4 library %s in wrong directory"), file_name);
739 }
740
741 /* Add library to list. */
742 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
743 {
744 /* Is soname already in list? */
745 if (strcmp (dlib_ptr->soname, soname) == 0)
746 {
747 /* Prefer a file to a link, otherwise check which one
748 is newer. */
749 if ((!is_link && dlib_ptr->is_link)
750 || (is_link == dlib_ptr->is_link
751 && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
752 {
753 /* It's newer - add it. */
754 /* Flag should be the same - sanity check. */
755 if (dlib_ptr->flag != flag)
756 {
757 if (dlib_ptr->flag == FLAG_ELF
758 && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
759 dlib_ptr->flag = flag;
760 else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
761 || dlib_ptr->flag == FLAG_ELF_LIBC6)
762 && flag == FLAG_ELF)
763 dlib_ptr->flag = flag;
764 else
765 error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
766 dlib_ptr->name, direntry->d_name, entry->path);
767 }
768 free (dlib_ptr->name);
769 dlib_ptr->name = xstrdup (direntry->d_name);
770 dlib_ptr->is_link = is_link;
771 }
772 /* Don't add this library, abort loop. */
773 /* Also free soname, since it's dynamically allocated. */
774 free (soname);
775 break;
776 }
777 }
778 /* Add the library if it's not already in. */
779 if (dlib_ptr == NULL)
780 {
781 dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
782 dlib_ptr->name = xstrdup (direntry->d_name);
783 dlib_ptr->flag = flag;
784 dlib_ptr->soname = soname;
785 dlib_ptr->is_link = is_link;
786 /* Add at head of list. */
787 dlib_ptr->next = dlibs;
788 dlibs = dlib_ptr;
789 }
790 }
791
792 closedir (dir);
793
794 /* Now dlibs contains a list of all libs - add those to the cache
795 and created all symbolic links. */
796 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
797 {
798 /* Don't create links to links. */
799 if (dlib_ptr->is_link == 0)
800 create_links (dir_name, entry->path, dlib_ptr->name,
801 dlib_ptr->soname);
802 if (opt_build_cache)
803 add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
804 }
805
806 /* Free all resources. */
807 while (dlibs)
808 {
809 dlib_ptr = dlibs;
810 free (dlib_ptr->soname);
811 free (dlib_ptr->name);
812 dlibs = dlibs->next;
813 free (dlib_ptr);
814 }
815
816 if (opt_chroot && dir_name)
817 free (dir_name);
818 }
819
820 /* Search through all libraries. */
821 static void
822 search_dirs (void)
823 {
824 struct dir_entry *entry;
825
826 for (entry = dir_entries; entry != NULL; entry = entry->next)
827 search_dir (entry);
828
829 /* Free all allocated memory. */
830 while (dir_entries)
831 {
832 entry = dir_entries;
833 dir_entries = dir_entries->next;
834 free (entry->path);
835 free (entry);
836 }
837 }
838
839
840 /* Parse configuration file. */
841 static void
842 parse_conf (const char *filename)
843 {
844 FILE *file = NULL;
845 char *line = NULL;
846 const char *canon;
847 size_t len = 0;
848
849 if (opt_chroot)
850 {
851 canon = chroot_canon (opt_chroot, filename);
852 if (canon)
853 file = fopen (canon, "r");
854 else
855 canon = filename;
856 }
857 else
858 {
859 canon = filename;
860 file = fopen (filename, "r");
861 }
862
863 if (file == NULL)
864 {
865 error (0, errno, _("Can't open configuration file %s"), canon);
866 if (canon != filename)
867 free ((char *) canon);
868 return;
869 }
870
871 if (canon != filename)
872 free ((char *) canon);
873
874 do
875 {
876 ssize_t n = getline (&line, &len, file);
877 if (n < 0)
878 break;
879
880 if (line[n - 1] == '\n')
881 line[n - 1] = '\0';
882
883 /* Because the file format does not know any form of quoting we
884 can search forward for the next '#' character and if found
885 make it terminating the line. */
886 *strchrnul (line, '#') = '\0';
887
888 /* If the line is blank it is ignored. */
889 if (line[0] == '\0')
890 continue;
891
892 add_dir (line);
893 } while (!feof (file));
894
895 /* Free buffer and close file. */
896 free (line);
897 fclose (file);
898 }
899
900
901 int
902 main (int argc, char **argv)
903 {
904 int remaining;
905
906 /* Parse and process arguments. */
907 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
908
909 /* Remaining arguments are additional libraries if opt_manual_link
910 is not set. */
911 if (remaining != argc && !opt_manual_link)
912 {
913 int i;
914 for (i = remaining; i < argc; ++i)
915 add_dir (argv [i]);
916 }
917
918 if (opt_chroot)
919 {
920 /* Normalize the path a bit, we might need it for printing later. */
921 char *endp = strchr (opt_chroot, '\0');
922 while (endp > opt_chroot && endp[-1] == '/')
923 --endp;
924 *endp = '\0';
925 if (endp == opt_chroot)
926 opt_chroot = NULL;
927
928 if (opt_chroot)
929 {
930 /* It is faster to use chroot if we can. */
931 if (!chroot (opt_chroot))
932 {
933 if (chdir ("/"))
934 error (EXIT_FAILURE, errno, _("Can't chdir to /"));
935 opt_chroot = NULL;
936 }
937 }
938 }
939
940 if (cache_file == NULL)
941 {
942 cache_file = alloca (strlen (LD_SO_CACHE) + 1);
943 strcpy (cache_file, LD_SO_CACHE);
944 }
945
946 if (config_file == NULL)
947 config_file = LD_SO_CONF;
948
949 if (opt_print_cache)
950 {
951 if (opt_chroot)
952 {
953 char *p = chroot_canon (opt_chroot, cache_file);
954 if (p == NULL)
955 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
956 cache_file);
957 cache_file = p;
958 }
959 print_cache (cache_file);
960 if (opt_chroot)
961 free (cache_file);
962 exit (0);
963 }
964
965 if (opt_chroot)
966 {
967 /* Canonicalize the directory name of cache_file, not cache_file,
968 because we'll rename a temporary cache file to it. */
969 char *p = strrchr (cache_file, '/');
970 char *canon = chroot_canon (opt_chroot,
971 p ? (*p = '\0', cache_file) : "/");
972
973 if (canon == NULL)
974 {
975 error (EXIT_FAILURE, errno,
976 _("Can't open cache file directory %s\n"),
977 p ? cache_file : "/");
978 }
979
980 if (p)
981 ++p;
982 else
983 p = cache_file;
984
985 cache_file = alloca (strlen (canon) + strlen (p) + 2);
986 sprintf (cache_file, "%s/%s", canon, p);
987 free (canon);
988 }
989
990 if (opt_manual_link)
991 {
992 /* Link all given libraries manually. */
993 int i;
994
995 for (i = remaining; i < argc; ++i)
996 manual_link (argv [i]);
997
998 exit (0);
999 }
1000
1001
1002 if (opt_build_cache)
1003 init_cache ();
1004
1005 if (!opt_only_cline)
1006 {
1007 /* Always add the standard search paths. */
1008 add_dir (SLIBDIR);
1009 if (strcmp (SLIBDIR, LIBDIR))
1010 add_dir (LIBDIR);
1011
1012 parse_conf (config_file);
1013 }
1014
1015 search_dirs ();
1016
1017 if (opt_build_cache)
1018 save_cache (cache_file);
1019
1020 return 0;
1021 }