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