1/* Copyright (C) 1999-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
16
17#define PROCINFO_CLASS static
18#include <assert.h>
19#include <alloca.h>
20#include <argp.h>
21#include <dirent.h>
22#include <elf.h>
23#include <error.h>
24#include <errno.h>
25#include <inttypes.h>
26#include <libintl.h>
27#include <locale.h>
28#include <stdbool.h>
29#include <stdio.h>
30#include <stdio_ext.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <stdint.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#include <dl-hwcaps.h>
45#include <dl-is_dso.h>
46
47#include <dl-procinfo.h>
48
49#ifndef LD_SO_CONF
50# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
51#endif
52
53/* Get libc version number. */
54#include <version.h>
55
56#define PACKAGE _libc_intl_domainname
57
58/* List of directories to handle. */
59struct dir_entry
60{
61 char *path;
62 int flag;
63 ino64_t ino;
64 dev_t dev;
65 const char *from_file;
66 int from_line;
67
68 /* Non-NULL for subdirectories under a glibc-hwcaps subdirectory. */
69 struct glibc_hwcaps_subdirectory *hwcaps;
70
71 struct dir_entry *next;
72};
73
74/* The list is unsorted, contains no duplicates. Entries are added at
75 the end. */
76static struct dir_entry *dir_entries;
77
78/* Flags for different options. */
79/* Print Cache. */
80static int opt_print_cache;
81
82/* Be verbose. */
83int opt_verbose;
84
85/* Format to support. */
86enum opt_format opt_format = opt_format_new;
87
88/* Build cache. */
89static int opt_build_cache = 1;
90
91/* Enable symbolic link processing. If set, create or update symbolic
92 links, and remove stale symbolic links. */
93static int opt_link = 1;
94
95/* Only process directories specified on the command line. */
96static int opt_only_cline;
97
98/* Path to root for chroot. */
99static char *opt_chroot;
100
101/* Manually link given shared libraries. */
102static int opt_manual_link;
103
104/* Should we ignore an old auxiliary cache file? */
105static int opt_ignore_aux_cache;
106
107/* Cache file to use. */
108static char *cache_file;
109
110/* Configuration file. */
111static const char *config_file;
112
113/* Name and version of program. */
114static void print_version (FILE *stream, struct argp_state *state);
115void (*argp_program_version_hook) (FILE *, struct argp_state *)
116 = print_version;
117
118/* Function to print some extra text in the help message. */
119static char *more_help (int key, const char *text, void *input);
120
121/* Definitions of arguments for argp functions. */
122static const struct argp_option options[] =
123{
124 { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
125 { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
126 { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
127 { NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
128 { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
129 { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
130 { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
131 { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
132 { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
133 { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
134 { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
135 { NULL, 0, NULL, 0, NULL, 0 }
136};
137
138#define PROCINFO_CLASS static
139#include <dl-procinfo.c>
140
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, more_help, NULL
151};
152
153/* Handle program arguments. */
154static error_t
155parse_opt (int key, char *arg, struct argp_state *state)
156{
157 switch (key)
158 {
159 case 'C':
160 cache_file = arg;
161 /* Ignore auxiliary cache since we use non-standard cache. */
162 opt_ignore_aux_cache = 1;
163 break;
164 case 'f':
165 config_file = arg;
166 break;
167 case 'i':
168 opt_ignore_aux_cache = 1;
169 break;
170 case 'l':
171 opt_manual_link = 1;
172 break;
173 case 'N':
174 opt_build_cache = 0;
175 break;
176 case 'n':
177 opt_build_cache = 0;
178 opt_only_cline = 1;
179 break;
180 case 'p':
181 opt_print_cache = 1;
182 break;
183 case 'r':
184 opt_chroot = arg;
185 break;
186 case 'v':
187 opt_verbose = 1;
188 break;
189 case 'X':
190 opt_link = 0;
191 break;
192 case 'c':
193 if (strcmp (s1: arg, s2: "old") == 0)
194 opt_format = opt_format_old;
195 else if (strcmp (s1: arg, s2: "compat") == 0)
196 opt_format = opt_format_compat;
197 else if (strcmp (s1: arg, s2: "new") == 0)
198 opt_format = opt_format_new;
199 break;
200 default:
201 return ARGP_ERR_UNKNOWN;
202 }
203
204 return 0;
205}
206
207/* Print bug-reporting information in the help message. */
208static char *
209more_help (int key, const char *text, void *input)
210{
211 char *tp = NULL;
212 switch (key)
213 {
214 case ARGP_KEY_HELP_EXTRA:
215 /* We print some extra information. */
216 if (asprintf (ptr: &tp, gettext ("\
217For bug reporting instructions, please see:\n\
218%s.\n"), REPORT_BUGS_TO) < 0)
219 return NULL;
220 return tp;
221 default:
222 break;
223 }
224 return (char *) text;
225}
226
227/* Print the version information. */
228static void
229print_version (FILE *stream, struct argp_state *state)
230{
231 fprintf (stream: stream, format: "ldconfig %s%s\n", PKGVERSION, VERSION);
232 fprintf (stream: stream, gettext ("\
233Copyright (C) %s Free Software Foundation, Inc.\n\
234This is free software; see the source for copying conditions. There is NO\n\
235warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
236"), "2024");
237 fprintf (stream: stream, gettext ("Written by %s.\n"),
238 "Andreas Jaeger");
239}
240
241/* Allocate a new subdirectory with full path PATH under ENTRY, using
242 inode data from *ST. */
243static struct dir_entry *
244new_sub_entry (const struct dir_entry *entry, const char *path,
245 const struct stat *st)
246{
247 struct dir_entry *new_entry = xmalloc (n: sizeof (struct dir_entry));
248 new_entry->from_file = entry->from_file;
249 new_entry->from_line = entry->from_line;
250 new_entry->path = xstrdup (path);
251 new_entry->flag = entry->flag;
252 new_entry->hwcaps = NULL;
253 new_entry->next = NULL;
254 new_entry->ino = st->st_ino;
255 new_entry->dev = st->st_dev;
256 return new_entry;
257}
258
259/* Add a single directory entry. Return true if the directory is
260 actually added (because it is not a duplicate). */
261static bool
262add_single_dir (struct dir_entry *entry, int verbose)
263{
264 struct dir_entry *ptr, *prev;
265 bool added = true;
266
267 ptr = dir_entries;
268 prev = ptr;
269 while (ptr != NULL)
270 {
271 /* Check for duplicates. */
272 if (ptr->ino == entry->ino && ptr->dev == entry->dev)
273 {
274 if (opt_verbose && verbose)
275 {
276 error (status: 0, errnum: 0, _("Path `%s' given more than once"), entry->path);
277 fprintf (stderr, _("(from %s:%d and %s:%d)\n"),
278 entry->from_file, entry->from_line,
279 ptr->from_file, ptr->from_line);
280 }
281 /* Use the newer information. */
282 ptr->flag = entry->flag;
283 free (ptr: entry->path);
284 free (ptr: entry);
285 added = false;
286 break;
287 }
288 prev = ptr;
289 ptr = ptr->next;
290 }
291 /* Is this the first entry? */
292 if (ptr == NULL && dir_entries == NULL)
293 dir_entries = entry;
294 else if (ptr == NULL)
295 prev->next = entry;
296 return added;
297}
298
299/* Check if PATH contains a "glibc-hwcaps" subdirectory. If so, queue
300 its subdirectories for glibc-hwcaps processing. */
301static void
302add_glibc_hwcaps_subdirectories (struct dir_entry *entry, const char *path)
303{
304 /* glibc-hwcaps subdirectories do not nest. */
305 assert (entry->hwcaps == NULL);
306
307 char *glibc_hwcaps;
308 if (asprintf (ptr: &glibc_hwcaps, fmt: "%s/" GLIBC_HWCAPS_SUBDIRECTORY, path) < 0)
309 error (EXIT_FAILURE, errno, _("Could not form glibc-hwcaps path"));
310
311 DIR *dir = opendir (name: glibc_hwcaps);
312 if (dir != NULL)
313 {
314 while (true)
315 {
316 errno = 0;
317 struct dirent64 *e = readdir64 (dirp: dir);
318 if (e == NULL)
319 {
320 if (errno == 0)
321 break;
322 else
323 error (EXIT_FAILURE, errno, _("Listing directory %s"), path);
324 }
325
326 /* Ignore hidden subdirectories, including "." and "..", and
327 regular files. File names containing a ':' cannot be
328 looked up by the dynamic loader, so skip those as
329 well. */
330 if (e->d_name[0] == '.' || e->d_type == DT_REG
331 || strchr (s: e->d_name, c: ':') != NULL)
332 continue;
333
334 /* See if this entry eventually resolves to a directory. */
335 struct stat st;
336 if (fstatat (dirfd (dir), file: e->d_name, buf: &st, flag: 0) < 0)
337 /* Ignore unreadable entries. */
338 continue;
339
340 if (S_ISDIR (st.st_mode))
341 {
342 /* This is a directory, so it needs to be scanned for
343 libraries, associated with the hwcaps implied by the
344 subdirectory name. */
345 char *new_path;
346 if (asprintf (ptr: &new_path, fmt: "%s/" GLIBC_HWCAPS_SUBDIRECTORY "/%s",
347 /* Use non-canonicalized path here. */
348 entry->path, e->d_name) < 0)
349 error (EXIT_FAILURE, errno,
350 _("Could not form glibc-hwcaps path"));
351 struct dir_entry *new_entry = new_sub_entry (entry, path: new_path,
352 st: &st);
353 free (ptr: new_path);
354 new_entry->hwcaps = new_glibc_hwcaps_subdirectory (name: e->d_name);
355 add_single_dir (entry: new_entry, verbose: 0);
356 }
357 }
358
359 closedir (dirp: dir);
360 }
361
362 free (ptr: glibc_hwcaps);
363}
364
365/* Add one directory to the list of directories to process. */
366static void
367add_dir_1 (const char *line, const char *from_file, int from_line)
368{
369 unsigned int i;
370 struct dir_entry *entry = xmalloc (n: sizeof (struct dir_entry));
371 entry->hwcaps = NULL;
372 entry->next = NULL;
373
374 entry->from_file = strdup (s: from_file);
375 entry->from_line = from_line;
376
377 entry->path = xstrdup (line);
378 entry->flag = FLAG_ELF_LIBC6;
379
380 /* Canonify path: for now only remove leading and trailing
381 whitespace and the trailing slashes. */
382 i = strlen (s: entry->path);
383
384 while (i > 0 && isspace (entry->path[i - 1]))
385 entry->path[--i] = '\0';
386
387 while (i > 0 && entry->path[i - 1] == '/')
388 entry->path[--i] = '\0';
389
390 if (i == 0)
391 {
392 free (ptr: entry->path);
393 free (ptr: entry);
394 return;
395 }
396
397 char *path = entry->path;
398 if (opt_chroot != NULL)
399 path = chroot_canon (chroot: opt_chroot, name: path);
400
401 struct stat stat_buf;
402 if (path == NULL || stat (file: path, buf: &stat_buf))
403 {
404 if (opt_verbose)
405 error (status: 0, errno, _("Can't stat %s"), entry->path);
406 free (ptr: entry->path);
407 free (ptr: entry);
408 }
409 else
410 {
411 entry->ino = stat_buf.st_ino;
412 entry->dev = stat_buf.st_dev;
413
414 if (add_single_dir (entry, verbose: 1))
415 /* Add glibc-hwcaps subdirectories if present. */
416 add_glibc_hwcaps_subdirectories (entry, path);
417 }
418
419 if (opt_chroot != NULL)
420 free (ptr: path);
421}
422
423static void
424add_dir (const char *line)
425{
426 add_dir_1 (line, from_file: "<builtin>", from_line: 0);
427}
428
429static int
430chroot_stat (const char *real_path, const char *path, struct stat *st)
431{
432 int ret;
433 char *canon_path;
434
435 if (!opt_chroot)
436 return stat (file: real_path, buf: st);
437
438 ret = lstat (file: real_path, buf: st);
439 if (ret || !S_ISLNK (st->st_mode))
440 return ret;
441
442 canon_path = chroot_canon (chroot: opt_chroot, name: path);
443 if (canon_path == NULL)
444 return -1;
445
446 ret = stat (file: canon_path, buf: st);
447 free (ptr: canon_path);
448 return ret;
449}
450
451/* Create a symbolic link from soname to libname in directory path. */
452static void
453create_links (const char *real_path, const char *path, const char *libname,
454 const char *soname)
455{
456 char *full_libname, *full_soname;
457 char *real_full_libname, *real_full_soname;
458 struct stat stat_lib, stat_so, lstat_so;
459 int do_link = 1;
460 int do_remove = 1;
461 /* XXX: The logics in this function should be simplified. */
462
463 /* Get complete path. */
464 full_libname = alloca (strlen (path) + strlen (libname) + 2);
465 full_soname = alloca (strlen (path) + strlen (soname) + 2);
466 sprintf (s: full_libname, format: "%s/%s", path, libname);
467 sprintf (s: full_soname, format: "%s/%s", path, soname);
468 if (opt_chroot != NULL)
469 {
470 real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
471 real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
472 sprintf (s: real_full_libname, format: "%s/%s", real_path, libname);
473 sprintf (s: real_full_soname, format: "%s/%s", real_path, soname);
474 }
475 else
476 {
477 real_full_libname = full_libname;
478 real_full_soname = full_soname;
479 }
480
481 /* Does soname already exist and point to the right library? */
482 if (chroot_stat (real_path: real_full_soname, path: full_soname, st: &stat_so) == 0)
483 {
484 if (chroot_stat (real_path: real_full_libname, path: full_libname, st: &stat_lib))
485 {
486 error (status: 0, errnum: 0, _("Can't stat %s\n"), full_libname);
487 return;
488 }
489 if (stat_lib.st_dev == stat_so.st_dev
490 && stat_lib.st_ino == stat_so.st_ino)
491 /* Link is already correct. */
492 do_link = 0;
493 else if (lstat (file: full_soname, buf: &lstat_so) == 0
494 && !S_ISLNK (lstat_so.st_mode))
495 {
496 error (status: 0, errnum: 0, _("%s is not a symbolic link\n"), full_soname);
497 do_link = 0;
498 do_remove = 0;
499 }
500 }
501 else if (lstat (file: real_full_soname, buf: &lstat_so) != 0
502 || !S_ISLNK (lstat_so.st_mode))
503 /* Unless it is a stale symlink, there is no need to remove. */
504 do_remove = 0;
505
506 if (opt_verbose)
507 printf (format: "\t%s -> %s", soname, libname);
508
509 if (do_link && opt_link)
510 {
511 /* Remove old link. */
512 if (do_remove)
513 if (unlink (name: real_full_soname))
514 {
515 error (status: 0, errnum: 0, _("Can't unlink %s"), full_soname);
516 do_link = 0;
517 }
518 /* Create symbolic link. */
519 if (do_link && symlink (from: libname, to: real_full_soname))
520 {
521 error (status: 0, errnum: 0, _("Can't link %s to %s"), full_soname, libname);
522 do_link = 0;
523 }
524 if (opt_verbose)
525 {
526 if (do_link)
527 fputs (_(" (changed)\n"), stdout);
528 else
529 fputs (_(" (SKIPPED)\n"), stdout);
530 }
531 }
532 else if (opt_verbose)
533 fputs (s: "\n", stdout);
534}
535
536/* Manually link the given library. */
537static void
538manual_link (char *library)
539{
540 char *path;
541 char *real_path;
542 char *real_library;
543 char *libname;
544 char *soname;
545 struct stat stat_buf;
546 int flag;
547 unsigned int isa_level;
548
549 /* Prepare arguments for create_links call. Split library name in
550 directory and filename first. Since path is allocated, we've got
551 to be careful to free at the end. */
552 path = xstrdup (library);
553 libname = strrchr (s: path, c: '/');
554
555 if (libname)
556 {
557 /* Successfully split names. Check if path is just "/" to avoid
558 an empty path. */
559 if (libname == path)
560 {
561 libname = library + 1;
562 path = xrealloc (o: path, n: 2);
563 strcpy (dest: path, src: "/");
564 }
565 else
566 {
567 *libname = '\0';
568 ++libname;
569 }
570 }
571 else
572 {
573 /* There's no path, construct one. */
574 libname = library;
575 path = xrealloc (o: path, n: 2);
576 strcpy (dest: path, src: ".");
577 }
578
579 if (opt_chroot != NULL)
580 {
581 real_path = chroot_canon (chroot: opt_chroot, name: path);
582 if (real_path == NULL)
583 {
584 error (status: 0, errno, _("Can't find %s"), path);
585 free (ptr: path);
586 return;
587 }
588 real_library = alloca (strlen (real_path) + strlen (libname) + 2);
589 sprintf (s: real_library, format: "%s/%s", real_path, libname);
590 }
591 else
592 {
593 real_path = path;
594 real_library = library;
595 }
596
597 /* Do some sanity checks first. */
598 if (lstat (file: real_library, buf: &stat_buf))
599 {
600 error (status: 0, errno, _("Cannot lstat %s"), library);
601 goto out;
602 }
603 /* We don't want links here! */
604 else if (!S_ISREG (stat_buf.st_mode))
605 {
606 error (status: 0, errnum: 0, _("Ignored file %s since it is not a regular file."),
607 library);
608 goto out;
609 }
610
611 if (process_file (real_file_name: real_library, file_name: library, lib: libname, flag: &flag, isa_level: &isa_level, soname: &soname,
612 is_link: 0, stat_buf: &stat_buf))
613 {
614 error (status: 0, errnum: 0, _("No link created since soname could not be found for %s"),
615 library);
616 goto out;
617 }
618 if (soname == NULL)
619 soname = xstrdup (libname);
620 create_links (real_path, path, libname, soname);
621 free (ptr: soname);
622out:
623 if (path != real_path)
624 free (ptr: real_path);
625 free (ptr: path);
626}
627
628
629/* Read a whole directory and search for libraries.
630 The purpose is two-fold:
631 - search for libraries which will be added to the cache
632 - create symbolic links to the soname for each library
633
634 This has to be done separately for each directory.
635
636 To keep track of which libraries to add to the cache and which
637 links to create, we save a list of all libraries.
638
639 The algorithm is basically:
640 for all libraries in the directory do
641 get soname of library
642 if soname is already in list
643 if new library is newer, replace entry
644 otherwise ignore this library
645 otherwise add library to list
646
647 For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
648 exist and both have the same soname, e.g. libxy.so, a symbolic link
649 is created from libxy.so.1.2 (the newer one) to libxy.so.
650 libxy.so.1.2 and libxy.so are added to the cache - but not
651 libxy.so.1.1. */
652
653/* Information for one library. */
654struct dlib_entry
655{
656 char *name;
657 char *soname;
658 int flag;
659 int is_link;
660 unsigned int isa_level;
661 struct dlib_entry *next;
662};
663
664/* Return true if the N bytes at NAME end with with the characters in
665 the string SUFFIX. (NAME[N + 1] does not have to be a null byte.)
666 Expected to be called with a string literal for SUFFIX. */
667static inline bool
668endswithn (const char *name, size_t n, const char *suffix)
669{
670 return (n >= strlen (s: suffix)
671 && memcmp (s1: name + n - strlen (s: suffix), s2: suffix,
672 n: strlen (s: suffix)) == 0);
673}
674
675/* Skip some temporary DSO files. These files may be partially written
676 and lead to ldconfig crashes when examined. */
677static bool
678skip_dso_based_on_name (const char *name, size_t len)
679{
680 /* Skip temporary files created by the prelink program. Files with
681 names like these are never really DSOs we want to look at. */
682 if (len >= sizeof (".#prelink#") - 1)
683 {
684 if (endswithn (name, n: len, suffix: ".#prelink#"))
685 return true;
686 if (len >= sizeof (".#prelink#.XXXXXX") - 1
687 && memcmp (s1: name + len - sizeof (".#prelink#.XXXXXX")
688 + 1, s2: ".#prelink#.", n: sizeof (".#prelink#.") - 1) == 0)
689 return true;
690 }
691 /* Skip temporary files created by RPM. */
692 if (memchr (s: name, c: ';', n: len) != NULL)
693 return true;
694 /* Skip temporary files created by dpkg. */
695 if (endswithn (name, n: len, suffix: ".dpkg-new")
696 || endswithn (name, n: len, suffix: ".dpkg-tmp"))
697 return true;
698 return false;
699}
700
701static void
702search_dir (const struct dir_entry *entry)
703{
704 if (opt_verbose)
705 {
706 if (entry->hwcaps == NULL)
707 printf (format: "%s:", entry->path);
708 else
709 printf (format: "%s: (hwcap: \"%s\")", entry->path,
710 glibc_hwcaps_subdirectory_name (entry->hwcaps));
711 printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line);
712 }
713
714 char *dir_name;
715 char *real_file_name;
716 char *file_name;
717 if (opt_chroot != NULL)
718 dir_name = chroot_canon (chroot: opt_chroot, name: entry->path);
719 else
720 dir_name = entry->path;
721
722 DIR *dir;
723 if (dir_name == NULL || (dir = opendir (name: dir_name)) == NULL)
724 {
725 if (opt_verbose)
726 error (status: 0, errno, _("Can't open directory %s"), entry->path);
727 if (opt_chroot != NULL)
728 free (ptr: dir_name);
729 return;
730 }
731
732 struct dirent64 *direntry;
733 struct dlib_entry *dlibs = NULL;
734 while ((direntry = readdir64 (dirp: dir)) != NULL)
735 {
736 int flag;
737 /* We only look at links and regular files. */
738 if (direntry->d_type != DT_UNKNOWN
739 && direntry->d_type != DT_LNK
740 && direntry->d_type != DT_REG
741 && direntry->d_type != DT_DIR)
742 continue;
743 /* Does this file look like a shared library? The dynamic linker
744 is also considered as shared library. */
745 if (!_dl_is_dso (name: direntry->d_name)
746 && (direntry->d_type == DT_REG || entry->hwcaps == NULL))
747 continue;
748
749 size_t len = strlen (s: direntry->d_name);
750 if (skip_dso_based_on_name (name: direntry->d_name, len))
751 continue;
752 if (asprintf (ptr: &file_name, fmt: "%s/%s", entry->path, direntry->d_name) < 0)
753 error (EXIT_FAILURE, errno, _("Could not form library path"));
754 if (opt_chroot != NULL)
755 {
756 if (asprintf (ptr: &real_file_name, fmt: "%s/%s",
757 dir_name, direntry->d_name) < 0)
758 error (EXIT_FAILURE, errno, _("Could not form library path"));
759 }
760 else
761 real_file_name = xstrdup (file_name);
762
763 struct stat lstat_buf;
764 /* We optimize and try to do the lstat call only if needed. */
765 if (direntry->d_type != DT_UNKNOWN)
766 lstat_buf.st_mode = DTTOIF (direntry->d_type);
767 else
768 if (__glibc_unlikely (lstat (real_file_name, &lstat_buf)))
769 {
770 error (status: 0, errno, _("Cannot lstat %s"), file_name);
771 goto next;
772 }
773
774 struct stat stat_buf;
775 int is_link = S_ISLNK (lstat_buf.st_mode);
776 if (is_link)
777 {
778 /* In case of symlink, we check if the symlink refers to
779 a directory. */
780 char *target_name = real_file_name;
781 if (opt_chroot != NULL)
782 {
783 target_name = chroot_canon (chroot: opt_chroot, name: file_name);
784 if (target_name == NULL)
785 {
786 if (strstr (haystack: file_name, needle: ".so") == NULL)
787 error (status: 0, errnum: 0, _("Input file %s not found.\n"), file_name);
788 goto next;
789 }
790 }
791 if (__glibc_unlikely (stat (target_name, &stat_buf)))
792 {
793 if (opt_verbose)
794 error (status: 0, errno, _("Cannot stat %s"), file_name);
795
796 /* Remove stale symlinks. */
797 if (opt_link && strstr (haystack: direntry->d_name, needle: ".so."))
798 unlink (name: real_file_name);
799
800 if (opt_chroot != NULL)
801 free (ptr: target_name);
802
803 goto next;
804 }
805
806 if (opt_chroot != NULL)
807 free (ptr: target_name);
808
809 /* lstat_buf is later stored, update contents. */
810 lstat_buf.st_dev = stat_buf.st_dev;
811 lstat_buf.st_ino = stat_buf.st_ino;
812 lstat_buf.st_size = stat_buf.st_size;
813 lstat_buf.st_ctime = stat_buf.st_ctime;
814 }
815 else if (!S_ISREG (lstat_buf.st_mode))
816 goto next;
817
818 char *real_name;
819 if (opt_chroot != NULL && is_link)
820 {
821 real_name = chroot_canon (chroot: opt_chroot, name: file_name);
822 if (real_name == NULL)
823 {
824 if (strstr (haystack: file_name, needle: ".so") == NULL)
825 error (status: 0, errnum: 0, _("Input file %s not found.\n"), file_name);
826 goto next;
827 }
828 }
829 else
830 real_name = real_file_name;
831
832 /* Call lstat if not done yet. */
833 if (!is_link
834 && direntry->d_type != DT_UNKNOWN
835 && __builtin_expect (lstat (file: real_file_name, buf: &lstat_buf), 0))
836 {
837 error (status: 0, errno, _("Cannot lstat %s"), file_name);
838 goto next;
839 }
840
841 /* First search whether the auxiliary cache contains this
842 library already and it's not changed. */
843 char *soname;
844 unsigned int isa_level;
845 if (!search_aux_cache (stat_buf: &lstat_buf, flags: &flag, isa_level: &isa_level, soname: &soname))
846 {
847 if (process_file (real_file_name: real_name, file_name, lib: direntry->d_name, flag: &flag,
848 isa_level: &isa_level, soname: &soname, is_link, stat_buf: &lstat_buf))
849 {
850 if (real_name != real_file_name)
851 free (ptr: real_name);
852 goto next;
853 }
854 else if (opt_build_cache)
855 add_to_aux_cache (stat_buf: &lstat_buf, flags: flag, isa_level, soname);
856 }
857
858 if (soname == NULL)
859 soname = xstrdup (direntry->d_name);
860
861 /* A link may just point to itself. */
862 if (is_link)
863 {
864 /* If the path the link points to isn't its soname or it is not
865 the .so symlink for ld(1), we treat it as a normal file.
866
867 You should always do this:
868
869 libfoo.so -> SONAME -> Arbitrary package-chosen name.
870
871 e.g. libfoo.so -> libfoo.so.1 -> libfooimp.so.9.99.
872 Given a SONAME of libfoo.so.1.
873
874 You should *never* do this:
875
876 libfoo.so -> libfooimp.so.9.99
877
878 If you do, and your SONAME is libfoo.so.1, then libfoo.so
879 fails to point at the SONAME. In that case ldconfig may consider
880 libfoo.so as another implementation of SONAME and will create
881 symlinks against it causing problems when you try to upgrade
882 or downgrade. The problems will arise because ldconfig will,
883 depending on directory ordering, creat symlinks against libfoo.so
884 e.g. libfoo.so.1.2 -> libfoo.so, but when libfoo.so is removed
885 (typically by the removal of a development package not required
886 for the runtime) it will break the libfoo.so.1.2 symlink and the
887 application will fail to start. */
888 const char *real_base_name = basename (path: real_file_name);
889
890 if (strcmp (s1: real_base_name, s2: soname) != 0)
891 {
892 len = strlen (s: real_base_name);
893 if (len < strlen (s: ".so")
894 || strcmp (s1: real_base_name + len - strlen (s: ".so"), s2: ".so") != 0
895 || strncmp (s1: real_base_name, s2: soname, n: len) != 0)
896 is_link = 0;
897 }
898 }
899
900 if (real_name != real_file_name)
901 free (ptr: real_name);
902
903 if (is_link)
904 {
905 free (ptr: soname);
906 soname = xstrdup (direntry->d_name);
907 }
908
909 /* Some sanity checks to print warnings. */
910 if (opt_verbose)
911 {
912 if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6)
913 error (status: 0, errnum: 0, _("libc6 library %s in wrong directory"), file_name);
914 }
915
916 /* Add library to list. */
917 struct dlib_entry *dlib_ptr;
918 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
919 {
920 /* Is soname already in list? */
921 if (strcmp (s1: dlib_ptr->soname, s2: soname) == 0)
922 {
923 /* Prefer a file to a link, otherwise check which one
924 is newer. */
925 if ((!is_link && dlib_ptr->is_link)
926 || (is_link == dlib_ptr->is_link
927 && _dl_cache_libcmp (p1: dlib_ptr->name, p2: direntry->d_name) < 0))
928 {
929 /* It's newer - add it. */
930 /* Flag should be the same - sanity check. */
931 if (dlib_ptr->flag != flag)
932 error (status: 0, errnum: 0, _("libraries %s and %s in directory %s have same soname but different type."),
933 dlib_ptr->name, direntry->d_name, entry->path);
934 free (ptr: dlib_ptr->name);
935 dlib_ptr->name = xstrdup (direntry->d_name);
936 dlib_ptr->is_link = is_link;
937 dlib_ptr->isa_level = isa_level;
938 }
939 /* Don't add this library, abort loop. */
940 /* Also free soname, since it's dynamically allocated. */
941 free (ptr: soname);
942 break;
943 }
944 }
945 /* Add the library if it's not already in. */
946 if (dlib_ptr == NULL)
947 {
948 dlib_ptr = (struct dlib_entry *)xmalloc (n: sizeof (struct dlib_entry));
949 dlib_ptr->name = xstrdup (direntry->d_name);
950 dlib_ptr->soname = soname;
951 dlib_ptr->flag = flag;
952 dlib_ptr->is_link = is_link;
953 dlib_ptr->isa_level = isa_level;
954 /* Add at head of list. */
955 dlib_ptr->next = dlibs;
956 dlibs = dlib_ptr;
957 }
958
959 next:
960 free (ptr: file_name);
961 free (ptr: real_file_name);
962 }
963
964 closedir (dirp: dir);
965
966 /* Now dlibs contains a list of all libs - add those to the cache
967 and created all symbolic links. */
968 struct dlib_entry *dlib_ptr;
969 for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
970 {
971 /* The cached file name is the soname for non-glibc-hwcaps
972 subdirectories (relying on symbolic links; this helps with
973 library updates that change the file name), and the actual
974 file for glibc-hwcaps subdirectories. */
975 const char *filename;
976 if (entry->hwcaps == NULL)
977 {
978 /* Don't create links to links. */
979 if (dlib_ptr->is_link == 0)
980 create_links (real_path: dir_name, path: entry->path, libname: dlib_ptr->name,
981 soname: dlib_ptr->soname);
982 filename = dlib_ptr->soname;
983 }
984 else
985 {
986 /* Do not create links in glibc-hwcaps subdirectories, but
987 still log the cache addition. */
988 if (opt_verbose)
989 printf (format: "\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name);
990 filename = dlib_ptr->name;
991 }
992 if (opt_build_cache)
993 add_to_cache (path: entry->path, filename, soname: dlib_ptr->soname,
994 flags: dlib_ptr->flag, isa_level: dlib_ptr->isa_level, entry->hwcaps);
995 }
996
997 /* Free all resources. */
998 while (dlibs)
999 {
1000 dlib_ptr = dlibs;
1001 free (ptr: dlib_ptr->soname);
1002 free (ptr: dlib_ptr->name);
1003 dlibs = dlibs->next;
1004 free (ptr: dlib_ptr);
1005 }
1006
1007 if (opt_chroot != NULL && dir_name != NULL)
1008 free (ptr: dir_name);
1009}
1010
1011/* Search through all libraries. */
1012static void
1013search_dirs (void)
1014{
1015 struct dir_entry *entry;
1016
1017 for (entry = dir_entries; entry != NULL; entry = entry->next)
1018 search_dir (entry);
1019
1020 /* Free all allocated memory. */
1021 while (dir_entries)
1022 {
1023 entry = dir_entries;
1024 dir_entries = dir_entries->next;
1025 free (ptr: entry->path);
1026 free (ptr: entry);
1027 }
1028}
1029
1030
1031static void parse_conf_include (const char *config_file, unsigned int lineno,
1032 bool do_chroot, const char *pattern);
1033
1034/* Parse configuration file. */
1035static void
1036parse_conf (const char *filename, bool do_chroot)
1037{
1038 FILE *file = NULL;
1039 char *line = NULL;
1040 const char *canon;
1041 size_t len = 0;
1042 unsigned int lineno;
1043
1044 if (do_chroot && opt_chroot)
1045 {
1046 canon = chroot_canon (chroot: opt_chroot, name: filename);
1047 if (canon)
1048 file = fopen (filename: canon, modes: "r");
1049 else
1050 canon = filename;
1051 }
1052 else
1053 {
1054 canon = filename;
1055 file = fopen (filename: filename, modes: "r");
1056 }
1057
1058 if (file == NULL)
1059 {
1060 if (errno != ENOENT)
1061 error (status: 0, errno, _("\
1062Warning: ignoring configuration file that cannot be opened: %s"),
1063 canon);
1064 if (canon != filename)
1065 free (ptr: (char *) canon);
1066 return;
1067 }
1068
1069 /* No threads use this stream. */
1070 __fsetlocking (file, FSETLOCKING_BYCALLER);
1071
1072 if (canon != filename)
1073 free (ptr: (char *) canon);
1074
1075 lineno = 0;
1076 do
1077 {
1078 ssize_t n = getline (lineptr: &line, n: &len, stream: file);
1079 if (n < 0)
1080 break;
1081
1082 ++lineno;
1083 if (line[n - 1] == '\n')
1084 line[n - 1] = '\0';
1085
1086 /* Because the file format does not know any form of quoting we
1087 can search forward for the next '#' character and if found
1088 make it terminating the line. */
1089 *strchrnul (s: line, c: '#') = '\0';
1090
1091 /* Remove leading whitespace. NUL is no whitespace character. */
1092 char *cp = line;
1093 while (isspace (*cp))
1094 ++cp;
1095
1096 /* If the line is blank it is ignored. */
1097 if (cp[0] == '\0')
1098 continue;
1099
1100 if (!strncmp (s1: cp, s2: "include", n: 7) && isblank (cp[7]))
1101 {
1102 char *dir;
1103 cp += 8;
1104 while ((dir = strsep (stringp: &cp, delim: " \t")) != NULL)
1105 if (dir[0] != '\0')
1106 parse_conf_include (config_file: filename, lineno, do_chroot, pattern: dir);
1107 }
1108 else if (!strncasecmp (s1: cp, s2: "hwcap", n: 5) && isblank (cp[5]))
1109 error (status: 0, errnum: 0, _("%s:%u: hwcap directive ignored"), filename, lineno);
1110 else
1111 add_dir_1 (line: cp, from_file: filename, from_line: lineno);
1112 }
1113 while (!feof_unlocked (stream: file));
1114
1115 /* Free buffer and close file. */
1116 free (ptr: line);
1117 fclose (stream: file);
1118}
1119
1120/* Handle one word in an `include' line, a glob pattern of additional
1121 config files to read. */
1122static void
1123parse_conf_include (const char *config_file, unsigned int lineno,
1124 bool do_chroot, const char *pattern)
1125{
1126 if (opt_chroot != NULL && pattern[0] != '/')
1127 error (EXIT_FAILURE, errnum: 0,
1128 _("need absolute file name for configuration file when using -r"));
1129
1130 char *copy = NULL;
1131 if (pattern[0] != '/' && strchr (s: config_file, c: '/') != NULL)
1132 {
1133 if (asprintf (ptr: &copy, fmt: "%s/%s", dirname (strdupa (config_file)),
1134 pattern) < 0)
1135 error (EXIT_FAILURE, errnum: 0, _("memory exhausted"));
1136 pattern = copy;
1137 }
1138
1139 glob64_t gl;
1140 int result;
1141 if (do_chroot && opt_chroot)
1142 {
1143 char *canon = chroot_canon (chroot: opt_chroot, name: pattern);
1144 if (canon == NULL)
1145 return;
1146 result = glob64 (pattern: canon, flags: 0, NULL, pglob: &gl);
1147 free (ptr: canon);
1148 }
1149 else
1150 result = glob64 (pattern: pattern, flags: 0, NULL, pglob: &gl);
1151
1152 switch (result)
1153 {
1154 case 0:
1155 for (size_t i = 0; i < gl.gl_pathc; ++i)
1156 parse_conf (filename: gl.gl_pathv[i], false);
1157 globfree64 (pglob: &gl);
1158 break;
1159
1160 case GLOB_NOMATCH:
1161 break;
1162
1163 case GLOB_NOSPACE:
1164 errno = ENOMEM;
1165 /* Fall through. */
1166 case GLOB_ABORTED:
1167 if (opt_verbose)
1168 error (status: 0, errno, _("%s:%u: cannot read directory %s"),
1169 config_file, lineno, pattern);
1170 break;
1171
1172 default:
1173 abort ();
1174 break;
1175 }
1176
1177 free (ptr: copy);
1178}
1179
1180
1181int
1182main (int argc, char **argv)
1183{
1184 /* Set locale via LC_ALL. */
1185 setlocale (LC_ALL, locale: "");
1186
1187 /* But keep the C collation. That way `include' directives using
1188 globbing patterns are processed in a locale-independent order. */
1189 setlocale (LC_COLLATE, locale: "C");
1190
1191 /* Set the text message domain. */
1192 textdomain (domainname: _libc_intl_domainname);
1193
1194 /* Parse and process arguments. */
1195 int remaining;
1196 argp_parse (argp: &argp, argc: argc, argv: argv, flags: 0, arg_index: &remaining, NULL);
1197
1198 /* Remaining arguments are additional directories if opt_manual_link
1199 is not set. */
1200 if (remaining != argc && !opt_manual_link)
1201 {
1202 int i;
1203 for (i = remaining; i < argc; ++i)
1204 if (opt_build_cache && argv[i][0] != '/')
1205 error (EXIT_FAILURE, errnum: 0,
1206 _("relative path `%s' used to build cache"),
1207 argv[i]);
1208 else
1209 add_dir_1 (line: argv[i], from_file: "<cmdline>", from_line: 0);
1210 }
1211
1212 if (opt_chroot != NULL)
1213 {
1214 /* Normalize the path a bit, we might need it for printing later. */
1215 char *endp = strchr (s: opt_chroot, c: '\0');
1216 while (endp > opt_chroot && endp[-1] == '/')
1217 --endp;
1218 *endp = '\0';
1219 if (endp == opt_chroot)
1220 opt_chroot = NULL;
1221
1222 if (opt_chroot != NULL)
1223 {
1224 /* It is faster to use chroot if we can. */
1225 if (!chroot (path: opt_chroot))
1226 {
1227 if (chdir (path: "/"))
1228 error (EXIT_FAILURE, errno, _("Can't chdir to /"));
1229 opt_chroot = NULL;
1230 }
1231 }
1232 }
1233
1234 if (cache_file == NULL)
1235 {
1236 cache_file = alloca (strlen (LD_SO_CACHE) + 1);
1237 strcpy (dest: cache_file, LD_SO_CACHE);
1238 }
1239
1240 if (config_file == NULL)
1241 config_file = LD_SO_CONF;
1242
1243 if (opt_print_cache)
1244 {
1245 if (opt_chroot != NULL)
1246 {
1247 char *p = chroot_canon (chroot: opt_chroot, name: cache_file);
1248 if (p == NULL)
1249 error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
1250 cache_file);
1251 cache_file = p;
1252 }
1253 print_cache (cache_name: cache_file);
1254 if (opt_chroot != NULL)
1255 free (ptr: cache_file);
1256 exit (status: 0);
1257 }
1258
1259 if (opt_chroot != NULL)
1260 {
1261 /* Canonicalize the directory name of cache_file, not cache_file,
1262 because we'll rename a temporary cache file to it. */
1263 char *p = strrchr (s: cache_file, c: '/');
1264 char *canon = chroot_canon (chroot: opt_chroot,
1265 name: p ? (*p = '\0', cache_file) : "/");
1266
1267 if (canon == NULL)
1268 error (EXIT_FAILURE, errno,
1269 _("Can't open cache file directory %s\n"),
1270 p ? cache_file : "/");
1271
1272 if (p)
1273 ++p;
1274 else
1275 p = cache_file;
1276
1277 cache_file = alloca (strlen (canon) + strlen (p) + 2);
1278 sprintf (s: cache_file, format: "%s/%s", canon, p);
1279 free (ptr: canon);
1280 }
1281
1282 if (opt_manual_link)
1283 {
1284 /* Link all given libraries manually. */
1285 int i;
1286
1287 for (i = remaining; i < argc; ++i)
1288 manual_link (library: argv[i]);
1289
1290 exit (status: 0);
1291 }
1292
1293
1294 if (opt_build_cache)
1295 init_cache ();
1296
1297 if (!opt_only_cline)
1298 {
1299 parse_conf (filename: config_file, true);
1300
1301 /* Always add the standard search paths. */
1302 add_system_dir (SLIBDIR);
1303 if (strcmp (SLIBDIR, LIBDIR))
1304 add_system_dir (LIBDIR);
1305 }
1306
1307 const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
1308 if (opt_chroot != NULL)
1309 aux_cache_file = chroot_canon (chroot: opt_chroot, name: aux_cache_file);
1310
1311 if (! opt_ignore_aux_cache && aux_cache_file)
1312 load_aux_cache (aux_cache_name: aux_cache_file);
1313 else
1314 init_aux_cache ();
1315
1316 search_dirs ();
1317
1318 if (opt_build_cache)
1319 {
1320 save_cache (cache_name: cache_file);
1321 if (aux_cache_file)
1322 save_aux_cache (aux_cache_name: aux_cache_file);
1323 }
1324
1325 return 0;
1326}
1327

source code of glibc/elf/ldconfig.c