]> sourceware.org Git - glibc.git/blame - elf/ldconfig.c
(__argp_error, __argp_failure): Check result of __asprintf call and don't use string...
[glibc.git] / elf / ldconfig.c
CommitLineData
8e597a18 1/* Copyright (C) 1999,2000,2001,2002,2003,2004 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
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
591e1ffb
UD
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
41bdb6e2 13 Lesser General Public License for more details.
591e1ffb 14
41bdb6e2
AJ
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
591e1ffb 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>
5a35dfca 26#include <inttypes.h>
591e1ffb 27#include <libintl.h>
f57ebe29 28#include <stdbool.h>
591e1ffb 29#include <stdio.h>
c96873d7 30#include <stdio_ext.h>
591e1ffb
UD
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <sys/fcntl.h>
35#include <sys/mman.h>
36#include <sys/stat.h>
37#include <sys/types.h>
8e115d80
RM
38#include <glob.h>
39#include <libgen.h>
591e1ffb
UD
40
41#include "ldconfig.h"
45eca4d1 42#include "dl-cache.h"
591e1ffb 43
45eca4d1 44#include "dl-procinfo.h"
591e1ffb
UD
45
46#ifndef LD_SO_CONF
8ca91b36 47# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
591e1ffb
UD
48#endif
49
50/* Get libc version number. */
51#include <version.h>
52
53#define PACKAGE _libc_intl_domainname
54
591e1ffb
UD
55static const struct
56{
57 const char *name;
58 int flag;
a986484f 59} lib_types[] =
591e1ffb
UD
60{
61 {"libc4", FLAG_LIBC4},
62 {"libc5", FLAG_ELF_LIBC5},
63 {"libc6", FLAG_ELF_LIBC6},
64 {"glibc2", FLAG_ELF_LIBC6}
45eca4d1 65};
591e1ffb
UD
66
67
68/* List of directories to handle. */
69struct dir_entry
70{
71 char *path;
72 int flag;
4ceae915
AJ
73 ino64_t ino;
74 dev_t dev;
591e1ffb
UD
75 struct dir_entry *next;
76};
77
78/* The list is unsorted, contains no duplicates. Entries are added at
79 the end. */
80static struct dir_entry *dir_entries;
81
82/* Flags for different options. */
83/* Print Cache. */
c96873d7 84static int opt_print_cache;
591e1ffb
UD
85
86/* Be verbose. */
c96873d7 87int opt_verbose;
591e1ffb 88
45eca4d1
UD
89/* Format to support. */
90/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
91int opt_format = 1;
92
591e1ffb
UD
93/* Build cache. */
94static int opt_build_cache = 1;
95
96/* Generate links. */
97static int opt_link = 1;
98
99/* Only process directories specified on the command line. */
c96873d7 100static int opt_only_cline;
591e1ffb
UD
101
102/* Path to root for chroot. */
103static char *opt_chroot;
104
b85697f6 105/* Manually link given shared libraries. */
c96873d7 106static int opt_manual_link;
b85697f6 107
591e1ffb 108/* Cache file to use. */
b4a555d6 109static char *cache_file;
591e1ffb
UD
110
111/* Configuration file. */
112static const char *config_file;
113
0cfbb8c6
UD
114/* Mask to use for important hardware capabilities. */
115static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
116
591e1ffb
UD
117/* Name and version of program. */
118static void print_version (FILE *stream, struct argp_state *state);
119void (*argp_program_version_hook) (FILE *, struct argp_state *)
120 = print_version;
121
122/* Definitions of arguments for argp functions. */
123static const struct argp_option options[] =
124{
125 { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
126 { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
127 { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
128 { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
129 { NULL, 'r', "ROOT", 0, N_("Change to and use ROOT as root directory"), 0},
130 { NULL, 'C', "CACHE", 0, N_("Use CACHE as cache file"), 0},
131 { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 0},
132 { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
b85697f6 133 { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
45eca4d1 134 { "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0},
591e1ffb
UD
135 { NULL, 0, NULL, 0, NULL, 0 }
136};
137
11bf8ce1
UD
138#define PROCINFO_CLASS static
139#include <dl-procinfo.c>
140
591e1ffb
UD
141/* Short description of program. */
142static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
143
144/* Prototype for option handler. */
145static error_t parse_opt (int key, char *arg, struct argp_state *state);
146
147/* Data structure to communicate with argp functions. */
148static struct argp argp =
149{
150 options, parse_opt, NULL, doc, NULL, NULL, NULL
151};
152
a6c1c03a
AJ
153/* Check if string corresponds to an important hardware capability or
154 a platform. */
45eca4d1 155static int
a6c1c03a 156is_hwcap_platform (const char *name)
45eca4d1
UD
157{
158 int hwcap_idx = _dl_string_hwcap (name);
8ca91b36 159
0cfbb8c6 160 if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
45eca4d1 161 return 1;
a6c1c03a
AJ
162
163 hwcap_idx = _dl_string_platform (name);
164 if (hwcap_idx != -1)
165 return 1;
166
676fde70
UD
167#ifdef USE_TLS
168 if (strcmp (name, "tls") == 0)
169 return 1;
170#endif
171
45eca4d1
UD
172 return 0;
173}
174
a6c1c03a
AJ
175/* Get hwcap (including platform) encoding of path. */
176static uint64_t
45eca4d1
UD
177path_hwcap (const char *path)
178{
179 char *str = xstrdup (path);
180 char *ptr;
a6c1c03a
AJ
181 uint64_t hwcap = 0;
182 uint64_t h;
45eca4d1
UD
183
184 size_t len;
185
186 len = strlen (str);
187 if (str[len] == '/')
188 str[len] = '\0';
189
190 /* Search pathname from the end and check for hwcap strings. */
191 for (;;)
192 {
193 ptr = strrchr (str, '/');
194
195 if (ptr == NULL)
196 break;
197
a6c1c03a 198 h = _dl_string_hwcap (ptr + 1);
45eca4d1 199
59553897
UD
200 if (h == (uint64_t) -1)
201 {
202 h = _dl_string_platform (ptr + 1);
203 if (h == (uint64_t) -1)
676fde70
UD
204 {
205#ifdef USE_TLS
206 if (strcmp (ptr + 1, "tls") == 0)
207 h = 63;
208 else
209#endif
210 break;
211 }
59553897 212 }
a6c1c03a 213 hwcap += 1ULL << h;
591e1ffb 214
45eca4d1
UD
215 /* Search the next part of the path. */
216 *ptr = '\0';
217 }
218
219 free (str);
220 return hwcap;
221}
591e1ffb
UD
222
223/* Handle program arguments. */
224static error_t
225parse_opt (int key, char *arg, struct argp_state *state)
226{
227 switch (key)
228 {
229 case 'C':
230 cache_file = arg;
231 break;
232 case 'f':
233 config_file = arg;
234 break;
b85697f6
UD
235 case 'l':
236 opt_manual_link = 1;
237 break;
591e1ffb
UD
238 case 'N':
239 opt_build_cache = 0;
240 break;
241 case 'n':
242 opt_build_cache = 0;
243 opt_only_cline = 1;
244 break;
245 case 'p':
246 opt_print_cache = 1;
247 break;
248 case 'r':
249 opt_chroot = arg;
250 break;
251 case 'v':
252 opt_verbose = 1;
253 break;
254 case 'X':
255 opt_link = 0;
256 break;
45eca4d1
UD
257 case 'c':
258 if (strcmp (arg, "old") == 0)
259 opt_format = 0;
260 else if (strcmp (arg, "compat") == 0)
261 opt_format = 1;
262 else if (strcmp (arg, "new") == 0)
263 opt_format = 2;
264 break;
591e1ffb
UD
265 default:
266 return ARGP_ERR_UNKNOWN;
267 }
268
269 return 0;
270}
271
272/* Print the version information. */
273static void
274print_version (FILE *stream, struct argp_state *state)
275{
276 fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
277 fprintf (stream, gettext ("\
278Copyright (C) %s Free Software Foundation, Inc.\n\
279This is free software; see the source for copying conditions. There is NO\n\
280warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
8e597a18 281"), "2004");
591e1ffb
UD
282 fprintf (stream, gettext ("Written by %s.\n"),
283 "Andreas Jaeger");
284}
285
a8fd59b0
AJ
286/* Add a single directory entry. */
287static void
288add_single_dir (struct dir_entry *entry, int verbose)
289{
290 struct dir_entry *ptr, *prev;
291
292 ptr = dir_entries;
293 prev = ptr;
294 while (ptr != NULL)
295 {
296 /* Check for duplicates. */
4ceae915 297 if (ptr->ino == entry->ino && ptr->dev == entry->dev)
a8fd59b0
AJ
298 {
299 if (opt_verbose && verbose)
300 error (0, 0, _("Path `%s' given more than once"), entry->path);
301 /* Use the newer information. */
302 ptr->flag = entry->flag;
4ceae915 303 free (entry->path);
a8fd59b0
AJ
304 free (entry);
305 break;
306 }
307 prev = ptr;
308 ptr = ptr->next;
309 }
310 /* Is this the first entry? */
311 if (ptr == NULL && dir_entries == NULL)
312 dir_entries = entry;
313 else if (ptr == NULL)
314 prev->next = entry;
315}
316
591e1ffb
UD
317/* Add one directory to the list of directories to process. */
318static void
319add_dir (const char *line)
320{
321 char *equal_sign;
a8fd59b0 322 struct dir_entry *entry;
591e1ffb 323 unsigned int i;
4ceae915 324 struct stat64 stat_buf;
45eca4d1 325
591e1ffb
UD
326 entry = xmalloc (sizeof (struct dir_entry));
327 entry->next = NULL;
45eca4d1 328
591e1ffb
UD
329 /* Search for an '=' sign. */
330 entry->path = xstrdup (line);
331 equal_sign = strchr (entry->path, '=');
332 if (equal_sign)
333 {
334 *equal_sign = '\0';
335 ++equal_sign;
336 entry->flag = FLAG_ANY;
a986484f 337 for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
591e1ffb
UD
338 if (strcmp (equal_sign, lib_types[i].name) == 0)
339 {
340 entry->flag = lib_types[i].flag;
341 break;
342 }
343 if (entry->flag == FLAG_ANY)
344 error (0, 0, _("%s is not a known library type"), equal_sign);
345 }
346 else
347 {
348 entry->flag = FLAG_ANY;
349 }
350
69acbe9f
UD
351 /* Canonify path: for now only remove leading and trailing
352 whitespace and the trailing slashes slashes. */
591e1ffb 353 i = strlen (entry->path) - 1;
69acbe9f
UD
354
355 while (isspace (entry->path[i]) && i > 0)
356 entry->path[i--] = '\0';
357
591e1ffb 358 while (entry->path[i] == '/' && i > 0)
69acbe9f 359 entry->path[i--] = '\0';
45eca4d1 360
4ceae915
AJ
361 if (stat64 (entry->path, &stat_buf))
362 {
8645ad47
AJ
363 if (opt_verbose)
364 error (0, errno, _("Can't stat %s"), entry->path);
4ceae915
AJ
365 free (entry->path);
366 free (entry);
367 return;
368 }
369
370 entry->ino = stat_buf.st_ino;
371 entry->dev = stat_buf.st_dev;
372
373 add_single_dir (entry, 1);
591e1ffb
UD
374}
375
376
b4a555d6
UD
377static int
378chroot_stat (const char *real_path, const char *path, struct stat64 *st)
379{
380 int ret;
381 char *canon_path;
382
383 if (!opt_chroot)
384 return stat64 (real_path, st);
385
386 ret = lstat64 (real_path, st);
387 if (ret || !S_ISLNK (st->st_mode))
388 return ret;
389
390 canon_path = chroot_canon (opt_chroot, path);
391 if (canon_path == NULL)
392 return -1;
393
394 ret = stat64 (canon_path, st);
395 free (canon_path);
396 return ret;
397}
398
591e1ffb
UD
399/* Create a symbolic link from soname to libname in directory path. */
400static void
b4a555d6
UD
401create_links (const char *real_path, const char *path, const char *libname,
402 const char *soname)
591e1ffb 403{
7b0d235c 404 char *full_libname, *full_soname;
b4a555d6
UD
405 char *real_full_libname, *real_full_soname;
406 struct stat64 stat_lib, stat_so, lstat_so;
591e1ffb
UD
407 int do_link = 1;
408 int do_remove = 1;
409 /* XXX: The logics in this function should be simplified. */
45eca4d1 410
591e1ffb 411 /* Get complete path. */
7b0d235c 412 full_libname = alloca (strlen (path) + strlen (libname) + 2);
7c545dbe 413 full_soname = alloca (strlen (path) + strlen (soname) + 2);
7b0d235c
AJ
414 sprintf (full_libname, "%s/%s", path, libname);
415 sprintf (full_soname, "%s/%s", path, soname);
b4a555d6
UD
416 if (opt_chroot)
417 {
418 real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
7c545dbe 419 real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
b4a555d6
UD
420 sprintf (real_full_libname, "%s/%s", real_path, libname);
421 sprintf (real_full_soname, "%s/%s", real_path, soname);
422 }
423 else
424 {
425 real_full_libname = full_libname;
426 real_full_soname = full_soname;
427 }
591e1ffb
UD
428
429 /* Does soname already exist and point to the right library? */
b4a555d6 430 if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
591e1ffb 431 {
b4a555d6 432 if (chroot_stat (real_full_libname, full_libname, &stat_lib))
591e1ffb
UD
433 {
434 error (0, 0, _("Can't stat %s\n"), full_libname);
435 return;
436 }
437 if (stat_lib.st_dev == stat_so.st_dev
438 && stat_lib.st_ino == stat_so.st_ino)
439 /* Link is already correct. */
440 do_link = 0;
b4a555d6 441 else if (lstat64 (full_soname, &lstat_so) == 0
591e1ffb
UD
442 && !S_ISLNK (lstat_so.st_mode))
443 {
444 error (0, 0, _("%s is not a symbolic link\n"), full_soname);
445 do_link = 0;
446 do_remove = 0;
447 }
448 }
b4a555d6 449 else if (lstat64 (real_full_soname, &lstat_so) != 0
591e1ffb
UD
450 || !S_ISLNK (lstat_so.st_mode))
451 /* Unless it is a stale symlink, there is no need to remove. */
452 do_remove = 0;
453
454 if (opt_verbose)
455 printf ("\t%s -> %s", soname, libname);
456
457 if (do_link && opt_link)
458 {
459 /* Remove old link. */
460 if (do_remove)
b4a555d6 461 if (unlink (real_full_soname))
591e1ffb
UD
462 {
463 error (0, 0, _("Can't unlink %s"), full_soname);
464 do_link = 0;
465 }
466 /* Create symbolic link. */
b4a555d6 467 if (do_link && symlink (libname, real_full_soname))
591e1ffb
UD
468 {
469 error (0, 0, _("Can't link %s to %s"), full_soname, libname);
470 do_link = 0;
471 }
472 if (opt_verbose)
473 {
474 if (do_link)
475 fputs (_(" (changed)\n"), stdout);
476 else
477 fputs (_(" (SKIPPED)\n"), stdout);
478 }
479 }
480 else if (opt_verbose)
481 fputs ("\n", stdout);
482}
483
b85697f6
UD
484/* Manually link the given library. */
485static void
486manual_link (char *library)
487{
488 char *path;
b4a555d6
UD
489 char *real_path;
490 char *real_library;
b85697f6
UD
491 char *libname;
492 char *soname;
b4a555d6 493 struct stat64 stat_buf;
b85697f6 494 int flag;
a986484f 495 unsigned int osversion;
b85697f6
UD
496
497 /* Prepare arguments for create_links call. Split library name in
498 directory and filename first. Since path is allocated, we've got
499 to be careful to free at the end. */
500 path = xstrdup (library);
501 libname = strrchr (path, '/');
502
503 if (libname)
504 {
505 /* Successfully split names. Check if path is just "/" to avoid
506 an empty path. */
507 if (libname == path)
508 {
509 libname = library + 1;
510 path = xrealloc (path, 2);
511 strcpy (path, "/");
512 }
513 else
514 {
515 *libname = '\0';
516 ++libname;
517 }
518 }
519 else
520 {
521 /* There's no path, construct one. */
522 libname = library;
523 path = xrealloc (path, 2);
524 strcpy (path, ".");
525 }
526
b4a555d6
UD
527 if (opt_chroot)
528 {
529 real_path = chroot_canon (opt_chroot, path);
530 if (real_path == NULL)
531 {
532 error (0, errno, _("Can't find %s"), path);
533 free (path);
534 return;
535 }
536 real_library = alloca (strlen (real_path) + strlen (libname) + 2);
537 sprintf (real_library, "%s/%s", real_path, libname);
538 }
539 else
540 {
541 real_path = path;
542 real_library = library;
543 }
544
b85697f6 545 /* Do some sanity checks first. */
b4a555d6 546 if (lstat64 (real_library, &stat_buf))
b85697f6
UD
547 {
548 error (0, errno, _("Can't lstat %s"), library);
549 free (path);
550 return;
551 }
552 /* We don't want links here! */
553 else if (!S_ISREG (stat_buf.st_mode))
554 {
555 error (0, 0, _("Ignored file %s since it is not a regular file."),
556 library);
557 free (path);
558 return;
559 }
a986484f
UD
560 if (process_file (real_library, library, libname, &flag, &osversion,
561 &soname, 0))
b85697f6
UD
562 {
563 error (0, 0, _("No link created since soname could not be found for %s"),
564 library);
565 free (path);
566 return;
567 }
b4a555d6 568 create_links (real_path, path, libname, soname);
b85697f6
UD
569 free (soname);
570 free (path);
571}
572
573
591e1ffb
UD
574/* Read a whole directory and search for libraries.
575 The purpose is two-fold:
576 - search for libraries which will be added to the cache
577 - create symbolic links to the soname for each library
578
579 This has to be done separatly for each directory.
45eca4d1 580
591e1ffb
UD
581 To keep track of which libraries to add to the cache and which
582 links to create, we save a list of all libraries.
583
584 The algorithm is basically:
585 for all libraries in the directory do
586 get soname of library
587 if soname is already in list
588 if new library is newer, replace entry
589 otherwise ignore this library
590 otherwise add library to list
45eca4d1 591
591e1ffb
UD
592 For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
593 exist and both have the same soname, e.g. libxy.so, a symbolic link
594 is created from libxy.so.1.2 (the newer one) to libxy.so.
595 libxy.so.1.2 and libxy.so are added to the cache - but not
596 libxy.so.1.1. */
597
598/* Information for one library. */
45eca4d1 599struct dlib_entry
591e1ffb
UD
600{
601 char *name;
602 char *soname;
603 int flag;
604 int is_link;
a986484f 605 unsigned int osversion;
591e1ffb
UD
606 struct dlib_entry *next;
607};
608
609
610static void
611search_dir (const struct dir_entry *entry)
612{
613 DIR *dir;
2b510e91 614 struct dirent64 *direntry;
b4a555d6
UD
615 char *file_name, *dir_name, *real_file_name, *real_name;
616 int file_name_len, real_file_name_len, len;
591e1ffb
UD
617 char *soname;
618 struct dlib_entry *dlibs;
619 struct dlib_entry *dlib_ptr;
4ceae915
AJ
620 struct stat64 lstat_buf, stat_buf;
621 int is_link, is_dir;
a6c1c03a 622 uint64_t hwcap = path_hwcap (entry->path);
a986484f 623 unsigned int osversion;
45eca4d1 624
7b0d235c
AJ
625 file_name_len = PATH_MAX;
626 file_name = alloca (file_name_len);
f0189a54 627
591e1ffb
UD
628 dlibs = NULL;
629
630 if (opt_verbose)
45eca4d1
UD
631 {
632 if (hwcap != 0)
5a35dfca 633 printf ("%s: (hwcap: 0x%" PRIx64 ")\n", entry->path, hwcap);
45eca4d1
UD
634 else
635 printf ("%s:\n", entry->path);
636 }
637
b4a555d6
UD
638 if (opt_chroot)
639 {
640 dir_name = chroot_canon (opt_chroot, entry->path);
641 real_file_name_len = PATH_MAX;
642 real_file_name = alloca (real_file_name_len);
643 }
644 else
645 {
646 dir_name = entry->path;
647 real_file_name_len = 0;
648 real_file_name = file_name;
649 }
650
651 if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
591e1ffb
UD
652 {
653 if (opt_verbose)
654 error (0, errno, _("Can't open directory %s"), entry->path);
b4a555d6
UD
655 if (opt_chroot && dir_name)
656 free (dir_name);
591e1ffb
UD
657 return;
658 }
45eca4d1 659
2b510e91 660 while ((direntry = readdir64 (dir)) != NULL)
591e1ffb
UD
661 {
662 int flag;
663#ifdef _DIRENT_HAVE_D_TYPE
664 /* We only look at links and regular files. */
665 if (direntry->d_type != DT_UNKNOWN
666 && direntry->d_type != DT_LNK
45eca4d1
UD
667 && direntry->d_type != DT_REG
668 && direntry->d_type != DT_DIR)
591e1ffb
UD
669 continue;
670#endif /* _DIRENT_HAVE_D_TYPE */
45eca4d1
UD
671 /* Does this file look like a shared library or is it a hwcap
672 subdirectory? The dynamic linker is also considered as
673 shared library. */
674 if (((strncmp (direntry->d_name, "lib", 3) != 0
675 && strncmp (direntry->d_name, "ld-", 3) != 0)
676 || strstr (direntry->d_name, ".so") == NULL)
95ce33a5
UD
677 && (
678#ifdef _DIRENT_HAVE_D_TYPE
679 direntry->d_type == DT_REG ||
680#endif
681 !is_hwcap_platform (direntry->d_name)))
591e1ffb 682 continue;
7b0d235c
AJ
683 len = strlen (entry->path) + strlen (direntry->d_name);
684 if (len > file_name_len)
591e1ffb 685 {
7b0d235c
AJ
686 file_name_len = len + 1;
687 file_name = alloca (file_name_len);
b4a555d6
UD
688 if (!opt_chroot)
689 real_file_name = file_name;
690 }
691 sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
692 if (opt_chroot)
693 {
694 len = strlen (dir_name) + strlen (direntry->d_name);
695 if (len > real_file_name_len)
696 {
697 real_file_name_len = len + 1;
698 real_file_name = alloca (real_file_name_len);
699 }
700 sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
591e1ffb 701 }
7c3002f0
UD
702#ifdef _DIRENT_HAVE_D_TYPE
703 if (direntry->d_type != DT_UNKNOWN)
4ceae915 704 lstat_buf.st_mode = DTTOIF (direntry->d_type);
7c3002f0
UD
705 else
706#endif
95ce33a5 707 if (__builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
7c3002f0 708 {
95ce33a5 709 error (0, errno, _("Cannot lstat %s"), file_name);
7c3002f0
UD
710 continue;
711 }
712
4ceae915
AJ
713 is_link = S_ISLNK (lstat_buf.st_mode);
714 if (is_link)
715 {
716 /* In case of symlink, we check if the symlink refers to
717 a directory. */
95ce33a5 718 if (__builtin_expect (stat64 (real_file_name, &stat_buf), 0))
4ceae915 719 {
8645ad47 720 if (opt_verbose)
95ce33a5 721 error (0, errno, _("Cannot stat %s"), file_name);
647eb037
UD
722
723 /* Remove stale symlinks. */
724 if (strstr (direntry->d_name, ".so."))
725 unlink (real_file_name);
4ceae915
AJ
726 continue;
727 }
728 is_dir = S_ISDIR (stat_buf.st_mode);
729 }
730 else
731 is_dir = S_ISDIR (lstat_buf.st_mode);
732
733 if (is_dir && is_hwcap_platform (direntry->d_name))
45eca4d1 734 {
a8fd59b0
AJ
735 /* Handle subdirectory later. */
736 struct dir_entry *new_entry;
737
738 new_entry = xmalloc (sizeof (struct dir_entry));
7b0d235c 739 new_entry->path = xstrdup (file_name);
a8fd59b0
AJ
740 new_entry->flag = entry->flag;
741 new_entry->next = NULL;
4ceae915
AJ
742 if (is_link)
743 {
744 new_entry->ino = stat_buf.st_ino;
745 new_entry->dev = stat_buf.st_dev;
746 }
747 else
748 {
95ce33a5
UD
749#ifdef _DIRENT_HAVE_D_TYPE
750 /* We have filled in lstat only #ifndef
751 _DIRENT_HAVE_D_TYPE. Fill it in if needed. */
752 if (direntry->d_type != DT_UNKNOWN
753 && __builtin_expect (lstat64 (real_file_name, &lstat_buf),
754 0))
755 {
756 error (0, errno, _("Cannot lstat %s"), file_name);
757 free (new_entry->path);
758 free (new_entry);
759 continue;
760 }
761#endif
762
4ceae915
AJ
763 new_entry->ino = lstat_buf.st_ino;
764 new_entry->dev = lstat_buf.st_dev;
765 }
a8fd59b0 766 add_single_dir (new_entry, 0);
45eca4d1
UD
767 continue;
768 }
0f843f89 769 else if (!S_ISREG (lstat_buf.st_mode) && !is_link)
591e1ffb
UD
770 continue;
771
b4a555d6
UD
772 if (opt_chroot && is_link)
773 {
774 real_name = chroot_canon (opt_chroot, file_name);
775 if (real_name == NULL)
776 {
777 if (strstr (file_name, ".so") == NULL)
778 error (0, 0, _("Input file %s not found.\n"), file_name);
779 continue;
780 }
781 }
782 else
783 real_name = real_file_name;
591e1ffb 784
b4a555d6 785 if (process_file (real_name, file_name, direntry->d_name, &flag,
a986484f 786 &osversion, &soname, is_link))
b4a555d6
UD
787 {
788 if (real_name != real_file_name)
789 free (real_name);
790 continue;
791 }
792
82d8607d
UD
793
794 /* A link may just point to itself. */
591e1ffb
UD
795 if (is_link)
796 {
82d8607d
UD
797 /* If the path the link points to isn't its soname and it is not
798 .so symlink for ld(1) only, we treat it as a normal file. */
2fe98a4a 799 const char *real_base_name = basename (real_file_name);
82d8607d
UD
800
801 if (strcmp (real_base_name, soname) != 0)
802 {
803 len = strlen (real_base_name);
804 if (len < strlen (".so")
805 || strcmp (real_base_name + len - strlen (".so"), ".so") != 0
806 || strncmp (real_base_name, soname, len) != 0)
807 is_link = 0;
808 }
809 }
45eca4d1 810
395412a0
UD
811 if (real_name != real_file_name)
812 free (real_name);
813
82d8607d
UD
814 if (is_link)
815 {
816 free (soname);
817 soname = xstrdup (direntry->d_name);
818 }
819
591e1ffb
UD
820 if (flag == FLAG_ELF
821 && (entry->flag == FLAG_ELF_LIBC5
822 || entry->flag == FLAG_ELF_LIBC6))
823 flag = entry->flag;
824 /* Some sanity checks to print warnings. */
825 if (opt_verbose)
826 {
827 if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
828 && entry->flag != FLAG_ANY)
7b0d235c 829 error (0, 0, _("libc5 library %s in wrong directory"), file_name);
591e1ffb
UD
830 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
831 && entry->flag != FLAG_ANY)
7b0d235c 832 error (0, 0, _("libc6 library %s in wrong directory"), file_name);
591e1ffb
UD
833 if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
834 && entry->flag != FLAG_ANY)
7b0d235c 835 error (0, 0, _("libc4 library %s in wrong directory"), file_name);
591e1ffb 836 }
45eca4d1 837
591e1ffb
UD
838 /* Add library to list. */
839 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
840 {
841 /* Is soname already in list? */
842 if (strcmp (dlib_ptr->soname, soname) == 0)
843 {
844 /* Prefer a file to a link, otherwise check which one
845 is newer. */
846 if ((!is_link && dlib_ptr->is_link)
847 || (is_link == dlib_ptr->is_link
45eca4d1 848 && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
591e1ffb
UD
849 {
850 /* It's newer - add it. */
851 /* Flag should be the same - sanity check. */
852 if (dlib_ptr->flag != flag)
853 {
854 if (dlib_ptr->flag == FLAG_ELF
855 && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
856 dlib_ptr->flag = flag;
857 else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
858 || dlib_ptr->flag == FLAG_ELF_LIBC6)
859 && flag == FLAG_ELF)
860 dlib_ptr->flag = flag;
861 else
862 error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
863 dlib_ptr->name, direntry->d_name, entry->path);
864 }
865 free (dlib_ptr->name);
b15ff9d6 866 dlib_ptr->osversion = osversion;
591e1ffb
UD
867 dlib_ptr->name = xstrdup (direntry->d_name);
868 dlib_ptr->is_link = is_link;
869 }
870 /* Don't add this library, abort loop. */
871 /* Also free soname, since it's dynamically allocated. */
872 free (soname);
873 break;
874 }
875 }
876 /* Add the library if it's not already in. */
877 if (dlib_ptr == NULL)
878 {
879 dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
880 dlib_ptr->name = xstrdup (direntry->d_name);
881 dlib_ptr->flag = flag;
a986484f 882 dlib_ptr->osversion = osversion;
591e1ffb
UD
883 dlib_ptr->soname = soname;
884 dlib_ptr->is_link = is_link;
885 /* Add at head of list. */
886 dlib_ptr->next = dlibs;
887 dlibs = dlib_ptr;
888 }
889 }
890
891 closedir (dir);
892
893 /* Now dlibs contains a list of all libs - add those to the cache
894 and created all symbolic links. */
895 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
896 {
897 /* Don't create links to links. */
898 if (dlib_ptr->is_link == 0)
b4a555d6
UD
899 create_links (dir_name, entry->path, dlib_ptr->name,
900 dlib_ptr->soname);
591e1ffb 901 if (opt_build_cache)
a986484f
UD
902 add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
903 dlib_ptr->osversion, hwcap);
591e1ffb
UD
904 }
905
906 /* Free all resources. */
45eca4d1 907 while (dlibs)
591e1ffb
UD
908 {
909 dlib_ptr = dlibs;
910 free (dlib_ptr->soname);
911 free (dlib_ptr->name);
912 dlibs = dlibs->next;
913 free (dlib_ptr);
914 }
b4a555d6
UD
915
916 if (opt_chroot && dir_name)
917 free (dir_name);
591e1ffb
UD
918}
919
920/* Search through all libraries. */
921static void
922search_dirs (void)
923{
924 struct dir_entry *entry;
925
926 for (entry = dir_entries; entry != NULL; entry = entry->next)
927 search_dir (entry);
928
929 /* Free all allocated memory. */
930 while (dir_entries)
931 {
932 entry = dir_entries;
933 dir_entries = dir_entries->next;
934 free (entry->path);
935 free (entry);
936 }
937}
938
939
8e115d80
RM
940static void parse_conf_include (const char *config_file, unsigned int lineno,
941 bool do_chroot, const char *pattern);
942
591e1ffb
UD
943/* Parse configuration file. */
944static void
8e115d80 945parse_conf (const char *filename, bool do_chroot)
591e1ffb 946{
b4a555d6 947 FILE *file = NULL;
591e1ffb 948 char *line = NULL;
b4a555d6 949 const char *canon;
591e1ffb 950 size_t len = 0;
8e115d80 951 unsigned int lineno;
45eca4d1 952
8e115d80 953 if (do_chroot && opt_chroot)
b4a555d6
UD
954 {
955 canon = chroot_canon (opt_chroot, filename);
956 if (canon)
957 file = fopen (canon, "r");
958 else
959 canon = filename;
960 }
961 else
962 {
963 canon = filename;
964 file = fopen (filename, "r");
965 }
591e1ffb
UD
966
967 if (file == NULL)
968 {
b4a555d6
UD
969 error (0, errno, _("Can't open configuration file %s"), canon);
970 if (canon != filename)
971 free ((char *) canon);
591e1ffb
UD
972 return;
973 }
974
c96873d7
UD
975 /* No threads use this stream. */
976 __fsetlocking (file, FSETLOCKING_BYCALLER);
977
b4a555d6
UD
978 if (canon != filename)
979 free ((char *) canon);
980
8e115d80 981 lineno = 0;
591e1ffb
UD
982 do
983 {
984 ssize_t n = getline (&line, &len, file);
985 if (n < 0)
986 break;
987
8e115d80 988 ++lineno;
591e1ffb
UD
989 if (line[n - 1] == '\n')
990 line[n - 1] = '\0';
991
992 /* Because the file format does not know any form of quoting we
993 can search forward for the next '#' character and if found
994 make it terminating the line. */
995 *strchrnul (line, '#') = '\0';
996
69acbe9f
UD
997 /* Remove leading whitespace. NUL is no whitespace character. */
998 char *cp = line;
999 while (isspace (*cp))
1000 ++cp;
1001
591e1ffb 1002 /* If the line is blank it is ignored. */
69acbe9f 1003 if (cp[0] == '\0')
591e1ffb
UD
1004 continue;
1005
8e115d80
RM
1006 if (!strncmp (cp, "include", 7) && isblank (cp[7]))
1007 {
1008 char *dir;
1009 cp += 8;
1010 while ((dir = strsep (&cp, " \t")) != NULL)
1011 if (dir[0] != '\0')
1012 parse_conf_include (filename, lineno, do_chroot, dir);
1013 }
1014 else
1015 add_dir (cp);
69acbe9f
UD
1016 }
1017 while (!feof_unlocked (file));
591e1ffb
UD
1018
1019 /* Free buffer and close file. */
1020 free (line);
1021 fclose (file);
1022}
1023
8e115d80
RM
1024/* Handle one word in an `include' line, a glob pattern of additional
1025 config files to read. */
1026static void
1027parse_conf_include (const char *config_file, unsigned int lineno,
1028 bool do_chroot, const char *pattern)
1029{
1030 if (opt_chroot && pattern[0] != '/')
1031 error (EXIT_FAILURE, 0,
1032 _("need absolute file name for configuration file when using -r"));
1033
1034 char *copy = NULL;
1035 if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
1036 {
1037 asprintf (&copy, "%s/%s", dirname (strdupa (config_file)), pattern);
1038 pattern = copy;
1039 }
1040
1041 glob64_t gl;
1042 int result;
1043 if (do_chroot && opt_chroot)
1044 {
1045 char *canon = chroot_canon (opt_chroot, pattern);
1046 result = glob64 (canon ?: pattern, 0, NULL, &gl);
1047 free (canon);
1048 }
1049 else
1050 result = glob64 (pattern, 0, NULL, &gl);
1051
1052 switch (result)
1053 {
1054 case 0:
1055 for (size_t i = 0; i < gl.gl_pathc; ++i)
1056 parse_conf (gl.gl_pathv[i], false);
1057 globfree64 (&gl);
1058 break;
1059
1060 case GLOB_NOMATCH:
1061 break;
1062
1063 case GLOB_NOSPACE:
1064 errno = ENOMEM;
1065 case GLOB_ABORTED:
1066 if (opt_verbose)
1067 error (0, errno, _("%s:%u: cannot read directory %s"),
1068 config_file, lineno, pattern);
1069 break;
1070
1071 default:
1072 abort ();
1073 break;
1074 }
1075
1076 if (copy)
1077 free (copy);
1078}
1079
0cfbb8c6
UD
1080/* Honour LD_HWCAP_MASK. */
1081static void
1082set_hwcap (void)
1083{
1084 char *mask = getenv ("LD_HWCAP_MASK");
1085
1086 if (mask)
1087 hwcap_mask = strtoul (mask, NULL, 0);
1088}
1089
591e1ffb
UD
1090
1091int
1092main (int argc, char **argv)
1093{
1094 int remaining;
45eca4d1 1095
591e1ffb
UD
1096 /* Parse and process arguments. */
1097 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
1098
11bf8ce1 1099 /* Remaining arguments are additional directories if opt_manual_link
b85697f6
UD
1100 is not set. */
1101 if (remaining != argc && !opt_manual_link)
591e1ffb
UD
1102 {
1103 int i;
1104 for (i = remaining; i < argc; ++i)
11bf8ce1
UD
1105 if (opt_build_cache && argv[i][0] != '/')
1106 error (EXIT_FAILURE, 0,
1107 _("relative path `%s' used to build cache"),
1108 argv[i]);
1109 else
1110 add_dir (argv[i]);
591e1ffb
UD
1111 }
1112
0cfbb8c6
UD
1113 set_hwcap ();
1114
591e1ffb
UD
1115 if (opt_chroot)
1116 {
f0189a54
UD
1117 /* Normalize the path a bit, we might need it for printing later. */
1118 char *endp = strchr (opt_chroot, '\0');
b4a555d6 1119 while (endp > opt_chroot && endp[-1] == '/')
f0189a54
UD
1120 --endp;
1121 *endp = '\0';
b4a555d6
UD
1122 if (endp == opt_chroot)
1123 opt_chroot = NULL;
f0189a54 1124
b4a555d6
UD
1125 if (opt_chroot)
1126 {
1127 /* It is faster to use chroot if we can. */
1128 if (!chroot (opt_chroot))
1129 {
1130 if (chdir ("/"))
1131 error (EXIT_FAILURE, errno, _("Can't chdir to /"));
1132 opt_chroot = NULL;
1133 }
1134 }
1135 }
1136
1137 if (cache_file == NULL)
1138 {
1139 cache_file = alloca (strlen (LD_SO_CACHE) + 1);
1140 strcpy (cache_file, LD_SO_CACHE);
591e1ffb
UD
1141 }
1142
b4a555d6
UD
1143 if (config_file == NULL)
1144 config_file = LD_SO_CONF;
1145
591e1ffb
UD
1146 if (opt_print_cache)
1147 {
b4a555d6
UD
1148 if (opt_chroot)
1149 {
1150 char *p = chroot_canon (opt_chroot, cache_file);
1151 if (p == NULL)
1152 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
1153 cache_file);
1154 cache_file = p;
1155 }
591e1ffb 1156 print_cache (cache_file);
b4a555d6
UD
1157 if (opt_chroot)
1158 free (cache_file);
591e1ffb
UD
1159 exit (0);
1160 }
1161
b4a555d6
UD
1162 if (opt_chroot)
1163 {
1164 /* Canonicalize the directory name of cache_file, not cache_file,
1165 because we'll rename a temporary cache file to it. */
1166 char *p = strrchr (cache_file, '/');
1167 char *canon = chroot_canon (opt_chroot,
1168 p ? (*p = '\0', cache_file) : "/");
1169
1170 if (canon == NULL)
1171 {
1172 error (EXIT_FAILURE, errno,
1173 _("Can't open cache file directory %s\n"),
1174 p ? cache_file : "/");
1175 }
1176
1177 if (p)
1178 ++p;
1179 else
1180 p = cache_file;
1181
1182 cache_file = alloca (strlen (canon) + strlen (p) + 2);
1183 sprintf (cache_file, "%s/%s", canon, p);
1184 free (canon);
1185 }
1186
b85697f6
UD
1187 if (opt_manual_link)
1188 {
1189 /* Link all given libraries manually. */
1190 int i;
1191
1192 for (i = remaining; i < argc; ++i)
a986484f 1193 manual_link (argv[i]);
b85697f6
UD
1194
1195 exit (0);
1196 }
45eca4d1
UD
1197
1198
591e1ffb
UD
1199 if (opt_build_cache)
1200 init_cache ();
1201
1202 if (!opt_only_cline)
1203 {
8e115d80 1204 parse_conf (config_file, true);
334fcf2a 1205
591e1ffb 1206 /* Always add the standard search paths. */
bd89c0b5 1207 add_system_dir (SLIBDIR);
8ca91b36 1208 if (strcmp (SLIBDIR, LIBDIR))
bd89c0b5 1209 add_system_dir (LIBDIR);
591e1ffb 1210 }
45eca4d1 1211
591e1ffb
UD
1212 search_dirs ();
1213
1214 if (opt_build_cache)
1215 save_cache (cache_file);
1216
1217 return 0;
1218}
This page took 0.27665 seconds and 5 git commands to generate.