]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/ldconfig.c
Update.
[thirdparty/glibc.git] / elf / ldconfig.c
CommitLineData
45eca4d1 1/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
591e1ffb
UD
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
7b0d235c 20#include <alloca.h>
591e1ffb
UD
21#include <argp.h>
22#include <dirent.h>
9c95d361 23#include <elf.h>
591e1ffb
UD
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>
a6c1c03a 31#include <stdint.h>
591e1ffb
UD
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"
45eca4d1 38#include "dl-cache.h"
591e1ffb 39
45eca4d1
UD
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"
591e1ffb
UD
44
45#ifndef LD_SO_CONF
8ca91b36 46# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
591e1ffb
UD
47#endif
48
49/* Get libc version number. */
50#include <version.h>
51
52#define PACKAGE _libc_intl_domainname
53
54struct lib_entry
55 {
56 int flags;
a6c1c03a 57 uint64_t hwcap;
591e1ffb
UD
58 char *lib;
59 char *path;
60 };
61
62static 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}
45eca4d1 72};
591e1ffb
UD
73
74
75/* List of directories to handle. */
76struct 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. */
85static struct dir_entry *dir_entries;
86
87/* Flags for different options. */
88/* Print Cache. */
89static int opt_print_cache = 0;
90
91/* Be verbose. */
92int opt_verbose = 0;
93
45eca4d1
UD
94/* Format to support. */
95/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
96int opt_format = 1;
97
591e1ffb
UD
98/* Build cache. */
99static int opt_build_cache = 1;
100
101/* Generate links. */
102static int opt_link = 1;
103
104/* Only process directories specified on the command line. */
105static int opt_only_cline = 0;
106
107/* Path to root for chroot. */
108static char *opt_chroot;
109
b85697f6
UD
110/* Manually link given shared libraries. */
111static int opt_manual_link = 0;
112
591e1ffb 113/* Cache file to use. */
b4a555d6 114static char *cache_file;
591e1ffb
UD
115
116/* Configuration file. */
117static const char *config_file;
118
119/* Name and version of program. */
120static void print_version (FILE *stream, struct argp_state *state);
121void (*argp_program_version_hook) (FILE *, struct argp_state *)
122 = print_version;
123
124/* Definitions of arguments for argp functions. */
125static 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},
b85697f6 135 { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
45eca4d1 136 { "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0},
591e1ffb
UD
137 { NULL, 0, NULL, 0, NULL, 0 }
138};
139
140/* Short description of program. */
141static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
142
143/* Prototype for option handler. */
144static error_t parse_opt (int key, char *arg, struct argp_state *state);
145
146/* Data structure to communicate with argp functions. */
147static struct argp argp =
148{
149 options, parse_opt, NULL, doc, NULL, NULL, NULL
150};
151
a6c1c03a
AJ
152/* Check if string corresponds to an important hardware capability or
153 a platform. */
45eca4d1 154static int
a6c1c03a 155is_hwcap_platform (const char *name)
45eca4d1
UD
156{
157 int hwcap_idx = _dl_string_hwcap (name);
8ca91b36 158
45eca4d1
UD
159 if (hwcap_idx != -1 && ((1 << hwcap_idx) & HWCAP_IMPORTANT))
160 return 1;
a6c1c03a
AJ
161
162 hwcap_idx = _dl_string_platform (name);
163 if (hwcap_idx != -1)
164 return 1;
165
45eca4d1
UD
166 return 0;
167}
168
a6c1c03a
AJ
169/* Get hwcap (including platform) encoding of path. */
170static uint64_t
45eca4d1
UD
171path_hwcap (const char *path)
172{
173 char *str = xstrdup (path);
174 char *ptr;
a6c1c03a
AJ
175 uint64_t hwcap = 0;
176 uint64_t h;
45eca4d1
UD
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
a6c1c03a 192 h = _dl_string_hwcap (ptr + 1);
45eca4d1 193
59553897
UD
194 if (h == (uint64_t) -1)
195 {
196 h = _dl_string_platform (ptr + 1);
197 if (h == (uint64_t) -1)
198 break;
199 }
a6c1c03a 200 hwcap += 1ULL << h;
591e1ffb 201
45eca4d1
UD
202 /* Search the next part of the path. */
203 *ptr = '\0';
204 }
205
206 free (str);
207 return hwcap;
208}
591e1ffb
UD
209
210/* Handle program arguments. */
211static error_t
212parse_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;
b85697f6
UD
222 case 'l':
223 opt_manual_link = 1;
224 break;
591e1ffb
UD
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;
45eca4d1
UD
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;
591e1ffb
UD
252 default:
253 return ARGP_ERR_UNKNOWN;
254 }
255
256 return 0;
257}
258
259/* Print the version information. */
260static void
261print_version (FILE *stream, struct argp_state *state)
262{
263 fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
264 fprintf (stream, gettext ("\
265Copyright (C) %s Free Software Foundation, Inc.\n\
266This is free software; see the source for copying conditions. There is NO\n\
267warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
45eca4d1 268"), "2000");
591e1ffb
UD
269 fprintf (stream, gettext ("Written by %s.\n"),
270 "Andreas Jaeger");
271}
272
a8fd59b0
AJ
273/* Add a single directory entry. */
274static void
275add_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
591e1ffb
UD
303/* Add one directory to the list of directories to process. */
304static void
305add_dir (const char *line)
306{
307 char *equal_sign;
a8fd59b0 308 struct dir_entry *entry;
591e1ffb 309 unsigned int i;
45eca4d1 310
591e1ffb
UD
311 entry = xmalloc (sizeof (struct dir_entry));
312 entry->next = NULL;
45eca4d1 313
591e1ffb
UD
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 }
45eca4d1 343
a8fd59b0 344 add_single_dir (entry, 1);
591e1ffb
UD
345}
346
347
b4a555d6
UD
348static int
349chroot_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
591e1ffb
UD
370/* Create a symbolic link from soname to libname in directory path. */
371static void
b4a555d6
UD
372create_links (const char *real_path, const char *path, const char *libname,
373 const char *soname)
591e1ffb 374{
7b0d235c 375 char *full_libname, *full_soname;
b4a555d6
UD
376 char *real_full_libname, *real_full_soname;
377 struct stat64 stat_lib, stat_so, lstat_so;
591e1ffb
UD
378 int do_link = 1;
379 int do_remove = 1;
380 /* XXX: The logics in this function should be simplified. */
45eca4d1 381
591e1ffb 382 /* Get complete path. */
7b0d235c 383 full_libname = alloca (strlen (path) + strlen (libname) + 2);
7c545dbe 384 full_soname = alloca (strlen (path) + strlen (soname) + 2);
7b0d235c
AJ
385 sprintf (full_libname, "%s/%s", path, libname);
386 sprintf (full_soname, "%s/%s", path, soname);
b4a555d6
UD
387 if (opt_chroot)
388 {
389 real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
7c545dbe 390 real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
b4a555d6
UD
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 }
591e1ffb
UD
399
400 /* Does soname already exist and point to the right library? */
b4a555d6 401 if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
591e1ffb 402 {
b4a555d6 403 if (chroot_stat (real_full_libname, full_libname, &stat_lib))
591e1ffb
UD
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;
b4a555d6 412 else if (lstat64 (full_soname, &lstat_so) == 0
591e1ffb
UD
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 }
b4a555d6 420 else if (lstat64 (real_full_soname, &lstat_so) != 0
591e1ffb
UD
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)
b4a555d6 432 if (unlink (real_full_soname))
591e1ffb
UD
433 {
434 error (0, 0, _("Can't unlink %s"), full_soname);
435 do_link = 0;
436 }
437 /* Create symbolic link. */
b4a555d6 438 if (do_link && symlink (libname, real_full_soname))
591e1ffb
UD
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
b85697f6
UD
455/* Manually link the given library. */
456static void
457manual_link (char *library)
458{
459 char *path;
b4a555d6
UD
460 char *real_path;
461 char *real_library;
b85697f6
UD
462 char *libname;
463 char *soname;
b4a555d6 464 struct stat64 stat_buf;
b85697f6
UD
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
b4a555d6
UD
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
b85697f6 515 /* Do some sanity checks first. */
b4a555d6 516 if (lstat64 (real_library, &stat_buf))
b85697f6
UD
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 }
b4a555d6 530 if (process_file (real_library, library, libname, &flag, &soname, 0))
b85697f6
UD
531 {
532 error (0, 0, _("No link created since soname could not be found for %s"),
533 library);
534 free (path);
535 return;
536 }
b4a555d6 537 create_links (real_path, path, libname, soname);
b85697f6
UD
538 free (soname);
539 free (path);
540}
541
542
591e1ffb
UD
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.
45eca4d1 549
591e1ffb
UD
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
45eca4d1 560
591e1ffb
UD
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. */
45eca4d1 568struct dlib_entry
591e1ffb
UD
569{
570 char *name;
571 char *soname;
572 int flag;
573 int is_link;
574 struct dlib_entry *next;
575};
576
577
578static void
579search_dir (const struct dir_entry *entry)
580{
581 DIR *dir;
582 struct dirent *direntry;
b4a555d6
UD
583 char *file_name, *dir_name, *real_file_name, *real_name;
584 int file_name_len, real_file_name_len, len;
591e1ffb
UD
585 char *soname;
586 struct dlib_entry *dlibs;
587 struct dlib_entry *dlib_ptr;
b4a555d6 588 struct stat64 stat_buf;
591e1ffb 589 int is_link;
a6c1c03a 590 uint64_t hwcap = path_hwcap (entry->path);
45eca4d1 591
7b0d235c
AJ
592 file_name_len = PATH_MAX;
593 file_name = alloca (file_name_len);
f0189a54 594
591e1ffb
UD
595 dlibs = NULL;
596
597 if (opt_verbose)
45eca4d1
UD
598 {
599 if (hwcap != 0)
a6c1c03a 600 printf ("%s: (hwcap: 0x%Lx)\n", entry->path, hwcap);
45eca4d1
UD
601 else
602 printf ("%s:\n", entry->path);
603 }
604
b4a555d6
UD
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)
591e1ffb
UD
619 {
620 if (opt_verbose)
621 error (0, errno, _("Can't open directory %s"), entry->path);
b4a555d6
UD
622 if (opt_chroot && dir_name)
623 free (dir_name);
591e1ffb
UD
624 return;
625 }
45eca4d1 626
591e1ffb
UD
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
45eca4d1
UD
634 && direntry->d_type != DT_REG
635 && direntry->d_type != DT_DIR)
591e1ffb
UD
636 continue;
637#endif /* _DIRENT_HAVE_D_TYPE */
45eca4d1
UD
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)
a6c1c03a 644 && !is_hwcap_platform (direntry->d_name))
591e1ffb 645 continue;
7b0d235c
AJ
646 len = strlen (entry->path) + strlen (direntry->d_name);
647 if (len > file_name_len)
591e1ffb 648 {
7b0d235c
AJ
649 file_name_len = len + 1;
650 file_name = alloca (file_name_len);
b4a555d6
UD
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);
591e1ffb 664 }
7c3002f0
UD
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
b4a555d6 670 if (lstat64 (real_file_name, &stat_buf))
7c3002f0 671 {
7b0d235c 672 error (0, errno, _("Can't lstat %s"), file_name);
7c3002f0
UD
673 continue;
674 }
675
a6c1c03a 676 if (S_ISDIR (stat_buf.st_mode) && is_hwcap_platform (direntry->d_name))
45eca4d1 677 {
a8fd59b0
AJ
678 /* Handle subdirectory later. */
679 struct dir_entry *new_entry;
680
681 new_entry = xmalloc (sizeof (struct dir_entry));
7b0d235c 682 new_entry->path = xstrdup (file_name);
a8fd59b0
AJ
683 new_entry->flag = entry->flag;
684 new_entry->next = NULL;
685 add_single_dir (new_entry, 0);
45eca4d1
UD
686 continue;
687 }
591e1ffb
UD
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);
b4a555d6
UD
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;
591e1ffb 704
b4a555d6
UD
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);
591e1ffb
UD
715
716 /* Links will just point to itself. */
717 if (is_link)
718 {
719 free (soname);
720 soname = xstrdup (direntry->d_name);
721 }
45eca4d1 722
591e1ffb
UD
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)
7b0d235c 732 error (0, 0, _("libc5 library %s in wrong directory"), file_name);
591e1ffb
UD
733 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
734 && entry->flag != FLAG_ANY)
7b0d235c 735 error (0, 0, _("libc6 library %s in wrong directory"), file_name);
591e1ffb
UD
736 if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
737 && entry->flag != FLAG_ANY)
7b0d235c 738 error (0, 0, _("libc4 library %s in wrong directory"), file_name);
591e1ffb 739 }
45eca4d1 740
591e1ffb
UD
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
45eca4d1 751 && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
591e1ffb
UD
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)
b4a555d6
UD
800 create_links (dir_name, entry->path, dlib_ptr->name,
801 dlib_ptr->soname);
591e1ffb 802 if (opt_build_cache)
45eca4d1 803 add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
591e1ffb
UD
804 }
805
806 /* Free all resources. */
45eca4d1 807 while (dlibs)
591e1ffb
UD
808 {
809 dlib_ptr = dlibs;
810 free (dlib_ptr->soname);
811 free (dlib_ptr->name);
812 dlibs = dlibs->next;
813 free (dlib_ptr);
814 }
b4a555d6
UD
815
816 if (opt_chroot && dir_name)
817 free (dir_name);
591e1ffb
UD
818}
819
820/* Search through all libraries. */
821static void
822search_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. */
841static void
842parse_conf (const char *filename)
843{
b4a555d6 844 FILE *file = NULL;
591e1ffb 845 char *line = NULL;
b4a555d6 846 const char *canon;
591e1ffb 847 size_t len = 0;
45eca4d1 848
b4a555d6
UD
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 }
591e1ffb
UD
862
863 if (file == NULL)
864 {
b4a555d6
UD
865 error (0, errno, _("Can't open configuration file %s"), canon);
866 if (canon != filename)
867 free ((char *) canon);
591e1ffb
UD
868 return;
869 }
870
b4a555d6
UD
871 if (canon != filename)
872 free ((char *) canon);
873
591e1ffb
UD
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
901int
902main (int argc, char **argv)
903{
904 int remaining;
45eca4d1 905
591e1ffb
UD
906 /* Parse and process arguments. */
907 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
908
b85697f6
UD
909 /* Remaining arguments are additional libraries if opt_manual_link
910 is not set. */
911 if (remaining != argc && !opt_manual_link)
591e1ffb
UD
912 {
913 int i;
914 for (i = remaining; i < argc; ++i)
915 add_dir (argv [i]);
916 }
917
591e1ffb
UD
918 if (opt_chroot)
919 {
f0189a54
UD
920 /* Normalize the path a bit, we might need it for printing later. */
921 char *endp = strchr (opt_chroot, '\0');
b4a555d6 922 while (endp > opt_chroot && endp[-1] == '/')
f0189a54
UD
923 --endp;
924 *endp = '\0';
b4a555d6
UD
925 if (endp == opt_chroot)
926 opt_chroot = NULL;
f0189a54 927
b4a555d6
UD
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);
591e1ffb
UD
944 }
945
b4a555d6
UD
946 if (config_file == NULL)
947 config_file = LD_SO_CONF;
948
591e1ffb
UD
949 if (opt_print_cache)
950 {
b4a555d6
UD
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 }
591e1ffb 959 print_cache (cache_file);
b4a555d6
UD
960 if (opt_chroot)
961 free (cache_file);
591e1ffb
UD
962 exit (0);
963 }
964
b4a555d6
UD
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
b85697f6
UD
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 }
45eca4d1
UD
1000
1001
591e1ffb
UD
1002 if (opt_build_cache)
1003 init_cache ();
1004
1005 if (!opt_only_cline)
1006 {
1007 /* Always add the standard search paths. */
8ca91b36
UD
1008 add_dir (SLIBDIR);
1009 if (strcmp (SLIBDIR, LIBDIR))
1010 add_dir (LIBDIR);
591e1ffb
UD
1011
1012 parse_conf (config_file);
1013 }
45eca4d1 1014
591e1ffb
UD
1015 search_dirs ();
1016
1017 if (opt_build_cache)
1018 save_cache (cache_file);
1019
1020 return 0;
1021}