Blame elf/ldconfig.c

Packit 6c4009
/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Andreas Jaeger <aj@suse.de>, 1999.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#define PROCINFO_CLASS static
Packit Service ad495e
#include <assert.h>
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <argp.h>
Packit 6c4009
#include <dirent.h>
Packit 6c4009
#include <elf.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <inttypes.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdio_ext.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/fcntl.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <glob.h>
Packit 6c4009
#include <libgen.h>
Packit 6c4009
Packit 6c4009
#include <ldconfig.h>
Packit 6c4009
#include <dl-cache.h>
Packit Service ad495e
#include <dl-hwcaps.h>
Packit 6c4009
Packit 6c4009
#include <dl-procinfo.h>
Packit 6c4009
Packit Service c1780e
/* This subpath in search path entries is always supported and
Packit Service c1780e
   included in the cache for backwards compatibility.  */
Packit Service c1780e
#define TLS_SUBPATH "tls"
Packit Service c1780e
Packit Service c1780e
/* The MSB of the hwcap field is set for objects in TLS_SUBPATH
Packit Service c1780e
   directories.  There is always TLS support in glibc, so the dynamic
Packit Service c1780e
   loader does not check the bit directly.  But more hwcap bits make a
Packit Service c1780e
   an object more preferred, so the bit still has meaning.  */
Packit Service c1780e
#define TLS_HWCAP_BIT 63
Packit 6c4009
Packit 6c4009
#ifndef LD_SO_CONF
Packit 6c4009
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Get libc version number.  */
Packit 6c4009
#include <version.h>
Packit 6c4009
Packit 6c4009
#define PACKAGE _libc_intl_domainname
Packit 6c4009
Packit 6c4009
static const struct
Packit 6c4009
{
Packit 6c4009
  const char *name;
Packit 6c4009
  int flag;
Packit 6c4009
} lib_types[] =
Packit 6c4009
{
Packit 6c4009
  {"libc4", FLAG_LIBC4},
Packit 6c4009
  {"libc5", FLAG_ELF_LIBC5},
Packit 6c4009
  {"libc6", FLAG_ELF_LIBC6},
Packit 6c4009
  {"glibc2", FLAG_ELF_LIBC6}
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* List of directories to handle.  */
Packit 6c4009
struct dir_entry
Packit 6c4009
{
Packit 6c4009
  char *path;
Packit 6c4009
  int flag;
Packit 6c4009
  ino64_t ino;
Packit 6c4009
  dev_t dev;
Packit Service 63e04b
  const char *from_file;
Packit Service 63e04b
  int from_line;
Packit Service ad495e
Packit Service ad495e
  /* Non-NULL for subdirectories under a glibc-hwcaps subdirectory.  */
Packit Service ad495e
  struct glibc_hwcaps_subdirectory *hwcaps;
Packit Service ad495e
Packit 6c4009
  struct dir_entry *next;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* The list is unsorted, contains no duplicates.  Entries are added at
Packit 6c4009
   the end.  */
Packit 6c4009
static struct dir_entry *dir_entries;
Packit 6c4009
Packit 6c4009
/* Flags for different options.  */
Packit 6c4009
/* Print Cache.  */
Packit 6c4009
static int opt_print_cache;
Packit 6c4009
Packit 6c4009
/* Be verbose.  */
Packit 6c4009
int opt_verbose;
Packit 6c4009
Packit 6c4009
/* Format to support.  */
Packit Service 46292a
enum opt_format opt_format = opt_format_new;
Packit 6c4009
Packit 6c4009
/* Build cache.  */
Packit 6c4009
static int opt_build_cache = 1;
Packit 6c4009
Packit 6c4009
/* Enable symbolic link processing.  If set, create or update symbolic
Packit 6c4009
   links, and remove stale symbolic links.  */
Packit 6c4009
static int opt_link = 1;
Packit 6c4009
Packit 6c4009
/* Only process directories specified on the command line.  */
Packit 6c4009
static int opt_only_cline;
Packit 6c4009
Packit 6c4009
/* Path to root for chroot.  */
Packit 6c4009
static char *opt_chroot;
Packit 6c4009
Packit 6c4009
/* Manually link given shared libraries.  */
Packit 6c4009
static int opt_manual_link;
Packit 6c4009
Packit 6c4009
/* Should we ignore an old auxiliary cache file?  */
Packit 6c4009
static int opt_ignore_aux_cache;
Packit 6c4009
Packit 6c4009
/* Cache file to use.  */
Packit 6c4009
static char *cache_file;
Packit 6c4009
Packit 6c4009
/* Configuration file.  */
Packit 6c4009
static const char *config_file;
Packit 6c4009
Packit 6c4009
/* Mask to use for important hardware capabilities.  */
Packit 6c4009
static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
Packit 6c4009
Packit 6c4009
/* Name and version of program.  */
Packit 6c4009
static void print_version (FILE *stream, struct argp_state *state);
Packit 6c4009
void (*argp_program_version_hook) (FILE *, struct argp_state *)
Packit 6c4009
     = print_version;
Packit 6c4009
Packit 6c4009
/* Function to print some extra text in the help message.  */
Packit 6c4009
static char *more_help (int key, const char *text, void *input);
Packit 6c4009
Packit 6c4009
/* Definitions of arguments for argp functions.  */
Packit 6c4009
static const struct argp_option options[] =
Packit 6c4009
{
Packit 6c4009
  { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
Packit 6c4009
  { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
Packit 6c4009
  { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
Packit 6c4009
  { NULL, 'X', NULL, 0, N_("Don't update symbolic links"), 0},
Packit 6c4009
  { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
Packit 6c4009
  { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
Packit 6c4009
  { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
Packit 6c4009
  { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line.  Don't build cache."), 0},
Packit 6c4009
  { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
Packit Service 9915bc
  { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new (default), old, or compat"), 0},
Packit 6c4009
  { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
Packit 6c4009
  { NULL, 0, NULL, 0, NULL, 0 }
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#define PROCINFO_CLASS static
Packit 6c4009
#include <dl-procinfo.c>
Packit 6c4009
Packit 6c4009
/* Short description of program.  */
Packit 6c4009
static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
Packit 6c4009
Packit 6c4009
/* Prototype for option handler.  */
Packit 6c4009
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit 6c4009
Packit 6c4009
/* Data structure to communicate with argp functions.  */
Packit 6c4009
static struct argp argp =
Packit 6c4009
{
Packit 6c4009
  options, parse_opt, NULL, doc, NULL, more_help, NULL
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Check if string corresponds to an important hardware capability or
Packit 6c4009
   a platform.  */
Packit 6c4009
static int
Packit 6c4009
is_hwcap_platform (const char *name)
Packit 6c4009
{
Packit 6c4009
  int hwcap_idx = _dl_string_hwcap (name);
Packit 6c4009
Packit 6c4009
  /* Is this a normal hwcap for the machine like "fpu?"  */
Packit 6c4009
  if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
Packit 6c4009
    return 1;
Packit 6c4009
Packit 6c4009
  /* Is this a platform pseudo-hwcap like "i686?"  */
Packit 6c4009
  hwcap_idx = _dl_string_platform (name);
Packit 6c4009
  if (hwcap_idx != -1)
Packit 6c4009
    return 1;
Packit 6c4009
Packit Service c1780e
  /* Backwards-compatibility for the "tls" subdirectory.  */
Packit Service c1780e
  if (strcmp (name, TLS_SUBPATH) == 0)
Packit Service c1780e
    return 1;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Get hwcap (including platform) encoding of path.  */
Packit 6c4009
static uint64_t
Packit 6c4009
path_hwcap (const char *path)
Packit 6c4009
{
Packit 6c4009
  char *str = xstrdup (path);
Packit 6c4009
  char *ptr;
Packit 6c4009
  uint64_t hwcap = 0;
Packit 6c4009
  uint64_t h;
Packit 6c4009
Packit 6c4009
  size_t len;
Packit 6c4009
Packit 6c4009
  len = strlen (str);
Packit 6c4009
  if (str[len] == '/')
Packit 6c4009
    str[len] = '\0';
Packit 6c4009
Packit 6c4009
  /* Search pathname from the end and check for hwcap strings.  */
Packit 6c4009
  for (;;)
Packit 6c4009
    {
Packit 6c4009
      ptr = strrchr (str, '/');
Packit 6c4009
Packit 6c4009
      if (ptr == NULL)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      h = _dl_string_hwcap (ptr + 1);
Packit 6c4009
Packit 6c4009
      if (h == (uint64_t) -1)
Packit 6c4009
	{
Packit 6c4009
	  h = _dl_string_platform (ptr + 1);
Packit 6c4009
	  if (h == (uint64_t) -1)
Packit 6c4009
	    {
Packit Service c1780e
	      if (strcmp (ptr + 1, TLS_SUBPATH) == 0)
Packit Service c1780e
		h = TLS_HWCAP_BIT;
Packit Service c1780e
	      else
Packit 6c4009
		break;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      hwcap += 1ULL << h;
Packit 6c4009
Packit 6c4009
      /* Search the next part of the path.  */
Packit 6c4009
      *ptr = '\0';
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  free (str);
Packit 6c4009
  return hwcap;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Handle program arguments.  */
Packit 6c4009
static error_t
Packit 6c4009
parse_opt (int key, char *arg, struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  switch (key)
Packit 6c4009
    {
Packit 6c4009
    case 'C':
Packit 6c4009
      cache_file = arg;
Packit 6c4009
      /* Ignore auxiliary cache since we use non-standard cache.  */
Packit 6c4009
      opt_ignore_aux_cache = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'f':
Packit 6c4009
      config_file = arg;
Packit 6c4009
      break;
Packit 6c4009
    case 'i':
Packit 6c4009
      opt_ignore_aux_cache = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'l':
Packit 6c4009
      opt_manual_link = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'N':
Packit 6c4009
      opt_build_cache = 0;
Packit 6c4009
      break;
Packit 6c4009
    case 'n':
Packit 6c4009
      opt_build_cache = 0;
Packit 6c4009
      opt_only_cline = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'p':
Packit 6c4009
      opt_print_cache = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'r':
Packit 6c4009
      opt_chroot = arg;
Packit 6c4009
      break;
Packit 6c4009
    case 'v':
Packit 6c4009
      opt_verbose = 1;
Packit 6c4009
      break;
Packit 6c4009
    case 'X':
Packit 6c4009
      opt_link = 0;
Packit 6c4009
      break;
Packit 6c4009
    case 'c':
Packit 6c4009
      if (strcmp (arg, "old") == 0)
Packit Service 46292a
	opt_format = opt_format_old;
Packit 6c4009
      else if (strcmp (arg, "compat") == 0)
Packit Service 46292a
	opt_format = opt_format_compat;
Packit 6c4009
      else if (strcmp (arg, "new") == 0)
Packit Service 46292a
	opt_format = opt_format_new;
Packit 6c4009
      break;
Packit 6c4009
    default:
Packit 6c4009
      return ARGP_ERR_UNKNOWN;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Print bug-reporting information in the help message.  */
Packit 6c4009
static char *
Packit 6c4009
more_help (int key, const char *text, void *input)
Packit 6c4009
{
Packit 6c4009
  char *tp = NULL;
Packit 6c4009
  switch (key)
Packit 6c4009
    {
Packit 6c4009
    case ARGP_KEY_HELP_EXTRA:
Packit 6c4009
      /* We print some extra information.  */
Packit 6c4009
      if (asprintf (&tp, gettext ("\
Packit 6c4009
For bug reporting instructions, please see:\n\
Packit 6c4009
%s.\n"), REPORT_BUGS_TO) < 0)
Packit 6c4009
	return NULL;
Packit 6c4009
      return tp;
Packit 6c4009
    default:
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
  return (char *) text;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Print the version information.  */
Packit 6c4009
static void
Packit 6c4009
print_version (FILE *stream, struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  fprintf (stream, "ldconfig %s%s\n", PKGVERSION, VERSION);
Packit 6c4009
  fprintf (stream, gettext ("\
Packit 6c4009
Copyright (C) %s Free Software Foundation, Inc.\n\
Packit 6c4009
This is free software; see the source for copying conditions.  There is NO\n\
Packit 6c4009
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
Packit 6c4009
"), "2018");
Packit 6c4009
  fprintf (stream, gettext ("Written by %s.\n"),
Packit 6c4009
	   "Andreas Jaeger");
Packit 6c4009
}
Packit 6c4009
Packit Service 2bfe73
/* Allocate a new subdirectory with full path PATH under ENTRY, using
Packit Service 2bfe73
   inode data from *ST.  */
Packit Service 2bfe73
static struct dir_entry *
Packit Service 2bfe73
new_sub_entry (const struct dir_entry *entry, const char *path,
Packit Service 2bfe73
	       const struct stat64 *st)
Packit Service 2bfe73
{
Packit Service 2bfe73
  struct dir_entry *new_entry = xmalloc (sizeof (struct dir_entry));
Packit Service 2bfe73
  new_entry->from_file = entry->from_file;
Packit Service 2bfe73
  new_entry->from_line = entry->from_line;
Packit Service 2bfe73
  new_entry->path = xstrdup (path);
Packit Service 2bfe73
  new_entry->flag = entry->flag;
Packit Service ad495e
  new_entry->hwcaps = NULL;
Packit Service 2bfe73
  new_entry->next = NULL;
Packit Service 2bfe73
  new_entry->ino = st->st_ino;
Packit Service 2bfe73
  new_entry->dev = st->st_dev;
Packit Service 2bfe73
  return new_entry;
Packit Service 2bfe73
}
Packit Service 2bfe73
Packit Service ad495e
/* Add a single directory entry.  Return true if the directory is
Packit Service ad495e
   actually added (because it is not a duplicate).  */
Packit Service ad495e
static bool
Packit 6c4009
add_single_dir (struct dir_entry *entry, int verbose)
Packit 6c4009
{
Packit 6c4009
  struct dir_entry *ptr, *prev;
Packit Service ad495e
  bool added = true;
Packit 6c4009
Packit 6c4009
  ptr = dir_entries;
Packit 6c4009
  prev = ptr;
Packit 6c4009
  while (ptr != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* Check for duplicates.  */
Packit 6c4009
      if (ptr->ino == entry->ino && ptr->dev == entry->dev)
Packit 6c4009
	{
Packit 6c4009
	  if (opt_verbose && verbose)
Packit Service 63e04b
	    {
Packit Service 63e04b
	      error (0, 0, _("Path `%s' given more than once"), entry->path);
Packit Service 63e04b
	      fprintf (stderr, _("(from %s:%d and %s:%d)\n"),
Packit Service 63e04b
		       entry->from_file, entry->from_line,
Packit Service 63e04b
		       ptr->from_file, ptr->from_line);
Packit Service 63e04b
	    }
Packit 6c4009
	  /* Use the newer information.  */
Packit 6c4009
	  ptr->flag = entry->flag;
Packit 6c4009
	  free (entry->path);
Packit 6c4009
	  free (entry);
Packit Service ad495e
	  added = false;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      prev = ptr;
Packit 6c4009
      ptr = ptr->next;
Packit 6c4009
    }
Packit 6c4009
  /* Is this the first entry?  */
Packit 6c4009
  if (ptr == NULL && dir_entries == NULL)
Packit 6c4009
    dir_entries = entry;
Packit 6c4009
  else if (ptr == NULL)
Packit 6c4009
    prev->next = entry;
Packit Service ad495e
  return added;
Packit Service ad495e
}
Packit Service ad495e
Packit Service ad495e
/* Check if PATH contains a "glibc-hwcaps" subdirectory.  If so, queue
Packit Service ad495e
   its subdirectories for glibc-hwcaps processing.  */
Packit Service ad495e
static void
Packit Service ad495e
add_glibc_hwcaps_subdirectories (struct dir_entry *entry, const char *path)
Packit Service ad495e
{
Packit Service ad495e
  /* glibc-hwcaps subdirectories do not nest.  */
Packit Service ad495e
  assert (entry->hwcaps == NULL);
Packit Service ad495e
Packit Service ad495e
  char *glibc_hwcaps;
Packit Service ad495e
  if (asprintf (&glibc_hwcaps, "%s/" GLIBC_HWCAPS_SUBDIRECTORY, path) < 0)
Packit Service ad495e
    error (EXIT_FAILURE, errno, _("Could not form glibc-hwcaps path"));
Packit Service ad495e
Packit Service ad495e
  DIR *dir = opendir (glibc_hwcaps);
Packit Service ad495e
  if (dir != NULL)
Packit Service ad495e
    {
Packit Service ad495e
      while (true)
Packit Service ad495e
	{
Packit Service ad495e
	  errno = 0;
Packit Service ad495e
	  struct dirent64 *e = readdir64 (dir);
Packit Service ad495e
	  if (e == NULL)
Packit Service ad495e
	    {
Packit Service ad495e
	      if (errno == 0)
Packit Service ad495e
		break;
Packit Service ad495e
	      else
Packit Service ad495e
		error (EXIT_FAILURE, errno, _("Listing directory %s"), path);
Packit Service ad495e
	    }
Packit Service ad495e
Packit Service ad495e
	  /* Ignore hidden subdirectories, including "." and "..", and
Packit Service ad495e
	     regular files.  File names containing a ':' cannot be
Packit Service ad495e
	     looked up by the dynamic loader, so skip those as
Packit Service ad495e
	     well.  */
Packit Service ad495e
	  if (e->d_name[0] == '.' || e->d_type == DT_REG
Packit Service ad495e
	      || strchr (e->d_name, ':') != NULL)
Packit Service ad495e
	    continue;
Packit Service ad495e
Packit Service ad495e
	  /* See if this entry eventually resolves to a directory.  */
Packit Service ad495e
	  struct stat64 st;
Packit Service ad495e
	  if (fstatat64 (dirfd (dir), e->d_name, &st, 0) < 0)
Packit Service ad495e
	    /* Ignore unreadable entries.  */
Packit Service ad495e
	    continue;
Packit Service ad495e
Packit Service ad495e
	  if (S_ISDIR (st.st_mode))
Packit Service ad495e
	    {
Packit Service ad495e
	      /* This is a directory, so it needs to be scanned for
Packit Service ad495e
		 libraries, associated with the hwcaps implied by the
Packit Service ad495e
		 subdirectory name.  */
Packit Service ad495e
	      char *new_path;
Packit Service ad495e
	      if (asprintf (&new_path, "%s/" GLIBC_HWCAPS_SUBDIRECTORY "/%s",
Packit Service ad495e
			    /* Use non-canonicalized path here.  */
Packit Service ad495e
			    entry->path, e->d_name) < 0)
Packit Service ad495e
		error (EXIT_FAILURE, errno,
Packit Service ad495e
		       _("Could not form glibc-hwcaps path"));
Packit Service ad495e
	      struct dir_entry *new_entry = new_sub_entry (entry, new_path,
Packit Service ad495e
							   &st);
Packit Service ad495e
	      free (new_path);
Packit Service ad495e
	      new_entry->hwcaps = new_glibc_hwcaps_subdirectory (e->d_name);
Packit Service ad495e
	      add_single_dir (new_entry, 0);
Packit Service ad495e
	    }
Packit Service ad495e
	}
Packit Service ad495e
Packit Service ad495e
      closedir (dir);
Packit Service ad495e
    }
Packit Service ad495e
Packit Service ad495e
  free (glibc_hwcaps);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Add one directory to the list of directories to process.  */
Packit 6c4009
static void
Packit Service 63e04b
add_dir_1 (const char *line, const char *from_file, int from_line)
Packit 6c4009
{
Packit 6c4009
  unsigned int i;
Packit 6c4009
  struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
Packit Service ad495e
  entry->hwcaps = NULL;
Packit 6c4009
  entry->next = NULL;
Packit 6c4009
Packit Service 63e04b
  entry->from_file = strdup (from_file);
Packit Service 63e04b
  entry->from_line = from_line;
Packit Service 63e04b
Packit 6c4009
  /* Search for an '=' sign.  */
Packit 6c4009
  entry->path = xstrdup (line);
Packit 6c4009
  char *equal_sign = strchr (entry->path, '=');
Packit 6c4009
  if (equal_sign)
Packit 6c4009
    {
Packit 6c4009
      *equal_sign = '\0';
Packit 6c4009
      ++equal_sign;
Packit 6c4009
      entry->flag = FLAG_ANY;
Packit 6c4009
      for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
Packit 6c4009
	if (strcmp (equal_sign, lib_types[i].name) == 0)
Packit 6c4009
	  {
Packit 6c4009
	    entry->flag = lib_types[i].flag;
Packit 6c4009
	    break;
Packit 6c4009
	  }
Packit 6c4009
      if (entry->flag == FLAG_ANY)
Packit 6c4009
	error (0, 0, _("%s is not a known library type"), equal_sign);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      entry->flag = FLAG_ANY;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Canonify path: for now only remove leading and trailing
Packit 6c4009
     whitespace and the trailing slashes.  */
Packit 6c4009
  i = strlen (entry->path);
Packit 6c4009
Packit 6c4009
  while (i > 0 && isspace (entry->path[i - 1]))
Packit 6c4009
    entry->path[--i] = '\0';
Packit 6c4009
Packit 6c4009
  while (i > 0 && entry->path[i - 1] == '/')
Packit 6c4009
    entry->path[--i] = '\0';
Packit 6c4009
Packit 6c4009
  if (i == 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  char *path = entry->path;
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    path = chroot_canon (opt_chroot, path);
Packit 6c4009
Packit 6c4009
  struct stat64 stat_buf;
Packit 6c4009
  if (path == NULL || stat64 (path, &stat_buf))
Packit 6c4009
    {
Packit 6c4009
      if (opt_verbose)
Packit 6c4009
	error (0, errno, _("Can't stat %s"), entry->path);
Packit 6c4009
      free (entry->path);
Packit 6c4009
      free (entry);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      entry->ino = stat_buf.st_ino;
Packit 6c4009
      entry->dev = stat_buf.st_dev;
Packit 6c4009
Packit Service ad495e
      if (add_single_dir (entry, 1))
Packit Service ad495e
	/* Add glibc-hwcaps subdirectories if present.  */
Packit Service ad495e
	add_glibc_hwcaps_subdirectories (entry, path);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    free (path);
Packit 6c4009
}
Packit 6c4009
Packit Service 63e04b
static void
Packit Service 63e04b
add_dir (const char *line)
Packit Service 63e04b
{
Packit Service 63e04b
  add_dir_1 (line, "<builtin>", 0);
Packit Service 63e04b
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
chroot_stat (const char *real_path, const char *path, struct stat64 *st)
Packit 6c4009
{
Packit 6c4009
  int ret;
Packit 6c4009
  char *canon_path;
Packit 6c4009
Packit 6c4009
  if (!opt_chroot)
Packit 6c4009
    return stat64 (real_path, st);
Packit 6c4009
Packit 6c4009
  ret = lstat64 (real_path, st);
Packit 6c4009
  if (ret || !S_ISLNK (st->st_mode))
Packit 6c4009
    return ret;
Packit 6c4009
Packit 6c4009
  canon_path = chroot_canon (opt_chroot, path);
Packit 6c4009
  if (canon_path == NULL)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  ret = stat64 (canon_path, st);
Packit 6c4009
  free (canon_path);
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Create a symbolic link from soname to libname in directory path.  */
Packit 6c4009
static void
Packit 6c4009
create_links (const char *real_path, const char *path, const char *libname,
Packit 6c4009
	      const char *soname)
Packit 6c4009
{
Packit 6c4009
  char *full_libname, *full_soname;
Packit 6c4009
  char *real_full_libname, *real_full_soname;
Packit 6c4009
  struct stat64 stat_lib, stat_so, lstat_so;
Packit 6c4009
  int do_link = 1;
Packit 6c4009
  int do_remove = 1;
Packit 6c4009
  /* XXX: The logics in this function should be simplified.  */
Packit 6c4009
Packit 6c4009
  /* Get complete path.  */
Packit 6c4009
  full_libname = alloca (strlen (path) + strlen (libname) + 2);
Packit 6c4009
  full_soname = alloca (strlen (path) + strlen (soname) + 2);
Packit 6c4009
  sprintf (full_libname, "%s/%s", path, libname);
Packit 6c4009
  sprintf (full_soname, "%s/%s", path, soname);
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
Packit 6c4009
      real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
Packit 6c4009
      sprintf (real_full_libname, "%s/%s", real_path, libname);
Packit 6c4009
      sprintf (real_full_soname, "%s/%s", real_path, soname);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      real_full_libname = full_libname;
Packit 6c4009
      real_full_soname = full_soname;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Does soname already exist and point to the right library?  */
Packit 6c4009
  if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
Packit 6c4009
    {
Packit 6c4009
      if (chroot_stat (real_full_libname, full_libname, &stat_lib))
Packit 6c4009
	{
Packit 6c4009
	  error (0, 0, _("Can't stat %s\n"), full_libname);
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
      if (stat_lib.st_dev == stat_so.st_dev
Packit 6c4009
	  && stat_lib.st_ino == stat_so.st_ino)
Packit 6c4009
	/* Link is already correct.  */
Packit 6c4009
	do_link = 0;
Packit 6c4009
      else if (lstat64 (full_soname, &lstat_so) == 0
Packit 6c4009
	       && !S_ISLNK (lstat_so.st_mode))
Packit 6c4009
	{
Packit 6c4009
	  error (0, 0, _("%s is not a symbolic link\n"), full_soname);
Packit 6c4009
	  do_link = 0;
Packit 6c4009
	  do_remove = 0;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (lstat64 (real_full_soname, &lstat_so) != 0
Packit 6c4009
	   || !S_ISLNK (lstat_so.st_mode))
Packit 6c4009
    /* Unless it is a stale symlink, there is no need to remove.  */
Packit 6c4009
    do_remove = 0;
Packit 6c4009
Packit 6c4009
  if (opt_verbose)
Packit 6c4009
    printf ("\t%s -> %s", soname, libname);
Packit 6c4009
Packit 6c4009
  if (do_link && opt_link)
Packit 6c4009
    {
Packit 6c4009
      /* Remove old link.  */
Packit 6c4009
      if (do_remove)
Packit 6c4009
	if (unlink (real_full_soname))
Packit 6c4009
	  {
Packit 6c4009
	    error (0, 0, _("Can't unlink %s"), full_soname);
Packit 6c4009
	    do_link = 0;
Packit 6c4009
	  }
Packit 6c4009
      /* Create symbolic link.  */
Packit 6c4009
      if (do_link && symlink (libname, real_full_soname))
Packit 6c4009
	{
Packit 6c4009
	  error (0, 0, _("Can't link %s to %s"), full_soname, libname);
Packit 6c4009
	  do_link = 0;
Packit 6c4009
	}
Packit 6c4009
      if (opt_verbose)
Packit 6c4009
	{
Packit 6c4009
	  if (do_link)
Packit 6c4009
	    fputs (_(" (changed)\n"), stdout);
Packit 6c4009
	  else
Packit 6c4009
	    fputs (_(" (SKIPPED)\n"), stdout);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (opt_verbose)
Packit 6c4009
    fputs ("\n", stdout);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Manually link the given library.  */
Packit 6c4009
static void
Packit 6c4009
manual_link (char *library)
Packit 6c4009
{
Packit 6c4009
  char *path;
Packit 6c4009
  char *real_path;
Packit 6c4009
  char *real_library;
Packit 6c4009
  char *libname;
Packit 6c4009
  char *soname;
Packit 6c4009
  struct stat64 stat_buf;
Packit 6c4009
  int flag;
Packit 6c4009
  unsigned int osversion;
Packit 6c4009
Packit 6c4009
  /* Prepare arguments for create_links call.  Split library name in
Packit 6c4009
     directory and filename first.  Since path is allocated, we've got
Packit 6c4009
     to be careful to free at the end.  */
Packit 6c4009
  path = xstrdup (library);
Packit 6c4009
  libname = strrchr (path, '/');
Packit 6c4009
Packit 6c4009
  if (libname)
Packit 6c4009
    {
Packit 6c4009
      /* Successfully split names.  Check if path is just "/" to avoid
Packit 6c4009
	 an empty path.  */
Packit 6c4009
      if (libname == path)
Packit 6c4009
	{
Packit 6c4009
	  libname = library + 1;
Packit 6c4009
	  path = xrealloc (path, 2);
Packit 6c4009
	  strcpy (path, "/");
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  *libname = '\0';
Packit 6c4009
	  ++libname;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* There's no path, construct one. */
Packit 6c4009
      libname = library;
Packit 6c4009
      path = xrealloc (path, 2);
Packit 6c4009
      strcpy (path, ".");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      real_path = chroot_canon (opt_chroot, path);
Packit 6c4009
      if (real_path == NULL)
Packit 6c4009
	{
Packit 6c4009
	  error (0, errno, _("Can't find %s"), path);
Packit 6c4009
	  free (path);
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
      real_library = alloca (strlen (real_path) + strlen (libname) + 2);
Packit 6c4009
      sprintf (real_library, "%s/%s", real_path, libname);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      real_path = path;
Packit 6c4009
      real_library = library;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Do some sanity checks first.  */
Packit 6c4009
  if (lstat64 (real_library, &stat_buf))
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("Cannot lstat %s"), library);
Packit 6c4009
      free (path);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  /* We don't want links here!  */
Packit 6c4009
  else if (!S_ISREG (stat_buf.st_mode))
Packit 6c4009
    {
Packit 6c4009
      error (0, 0, _("Ignored file %s since it is not a regular file."),
Packit 6c4009
	     library);
Packit 6c4009
      free (path);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (process_file (real_library, library, libname, &flag, &osversion,
Packit 6c4009
		    &soname, 0, &stat_buf))
Packit 6c4009
    {
Packit 6c4009
      error (0, 0, _("No link created since soname could not be found for %s"),
Packit 6c4009
	     library);
Packit 6c4009
      free (path);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  if (soname == NULL)
Packit 6c4009
    soname = implicit_soname (libname, flag);
Packit 6c4009
  create_links (real_path, path, libname, soname);
Packit 6c4009
  free (soname);
Packit 6c4009
  free (path);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Read a whole directory and search for libraries.
Packit 6c4009
   The purpose is two-fold:
Packit 6c4009
   - search for libraries which will be added to the cache
Packit 6c4009
   - create symbolic links to the soname for each library
Packit 6c4009
Packit 6c4009
   This has to be done separatly for each directory.
Packit 6c4009
Packit 6c4009
   To keep track of which libraries to add to the cache and which
Packit 6c4009
   links to create, we save a list of all libraries.
Packit 6c4009
Packit 6c4009
   The algorithm is basically:
Packit 6c4009
   for all libraries in the directory do
Packit 6c4009
     get soname of library
Packit 6c4009
     if soname is already in list
Packit 6c4009
       if new library is newer, replace entry
Packit 6c4009
       otherwise ignore this library
Packit 6c4009
     otherwise add library to list
Packit 6c4009
Packit 6c4009
   For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
Packit 6c4009
   exist and both have the same soname, e.g. libxy.so, a symbolic link
Packit 6c4009
   is created from libxy.so.1.2 (the newer one) to libxy.so.
Packit 6c4009
   libxy.so.1.2 and libxy.so are added to the cache - but not
Packit 6c4009
   libxy.so.1.1.  */
Packit 6c4009
Packit 6c4009
/* Information for one library.  */
Packit 6c4009
struct dlib_entry
Packit 6c4009
{
Packit 6c4009
  char *name;
Packit 6c4009
  char *soname;
Packit 6c4009
  int flag;
Packit 6c4009
  int is_link;
Packit 6c4009
  unsigned int osversion;
Packit 6c4009
  struct dlib_entry *next;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
search_dir (const struct dir_entry *entry)
Packit 6c4009
{
Packit Service ad495e
  uint64_t hwcap;
Packit Service ad495e
  if (entry->hwcaps == NULL)
Packit Service 80c63c
    {
Packit Service ad495e
      hwcap = path_hwcap (entry->path);
Packit Service ad495e
      if (opt_verbose)
Packit Service ad495e
	{
Packit Service ad495e
	  if (hwcap != 0)
Packit Service ad495e
	    printf ("%s: (hwcap: %#.16" PRIx64 ")", entry->path, hwcap);
Packit Service ad495e
	  else
Packit Service ad495e
	    printf ("%s:", entry->path);
Packit Service ad495e
	}
Packit Service 80c63c
    }
Packit Service ad495e
  else
Packit Service ad495e
    {
Packit Service ad495e
      hwcap = 0;
Packit Service ad495e
      if (opt_verbose)
Packit Service ad495e
	printf ("%s: (hwcap: \"%s\")", entry->path,
Packit Service ad495e
		glibc_hwcaps_subdirectory_name (entry->hwcaps));
Packit Service ad495e
    }
Packit Service ad495e
  if (opt_verbose)
Packit Service ad495e
    printf (_(" (from %s:%d)\n"), entry->from_file, entry->from_line);
Packit 6c4009
Packit 6c4009
  char *dir_name;
Packit 6c4009
  char *real_file_name;
Packit 6c4009
  size_t real_file_name_len;
Packit 6c4009
  size_t file_name_len = PATH_MAX;
Packit 6c4009
  char *file_name = alloca (file_name_len);
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      dir_name = chroot_canon (opt_chroot, entry->path);
Packit 6c4009
      real_file_name_len = PATH_MAX;
Packit 6c4009
      real_file_name = alloca (real_file_name_len);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      dir_name = entry->path;
Packit 6c4009
      real_file_name_len = 0;
Packit 6c4009
      real_file_name = file_name;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  DIR *dir;
Packit 6c4009
  if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
Packit 6c4009
    {
Packit 6c4009
      if (opt_verbose)
Packit 6c4009
	error (0, errno, _("Can't open directory %s"), entry->path);
Packit 6c4009
      if (opt_chroot && dir_name)
Packit 6c4009
	free (dir_name);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  struct dirent64 *direntry;
Packit 6c4009
  struct dlib_entry *dlibs = NULL;
Packit 6c4009
  while ((direntry = readdir64 (dir)) != NULL)
Packit 6c4009
    {
Packit 6c4009
      int flag;
Packit 6c4009
      /* We only look at links and regular files.  */
Packit 6c4009
      if (direntry->d_type != DT_UNKNOWN
Packit 6c4009
	  && direntry->d_type != DT_LNK
Packit 6c4009
	  && direntry->d_type != DT_REG
Packit 6c4009
	  && direntry->d_type != DT_DIR)
Packit 6c4009
	continue;
Packit 6c4009
      /* Does this file look like a shared library or is it a hwcap
Packit Service ad495e
	 subdirectory (if not already processing a glibc-hwcaps
Packit Service ad495e
	 subdirectory)?  The dynamic linker is also considered as
Packit 6c4009
	 shared library.  */
Packit 6c4009
      if (((strncmp (direntry->d_name, "lib", 3) != 0
Packit 6c4009
	    && strncmp (direntry->d_name, "ld-", 3) != 0)
Packit 6c4009
	   || strstr (direntry->d_name, ".so") == NULL)
Packit 6c4009
	  && (direntry->d_type == DT_REG
Packit Service ad495e
	      || (entry->hwcaps == NULL
Packit Service ad495e
		  && !is_hwcap_platform (direntry->d_name))))
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      size_t len = strlen (direntry->d_name);
Packit 6c4009
      /* Skip temporary files created by the prelink program.  Files with
Packit 6c4009
	 names like these are never really DSOs we want to look at.  */
Packit 6c4009
      if (len >= sizeof (".#prelink#") - 1)
Packit 6c4009
	{
Packit 6c4009
	  if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1,
Packit 6c4009
		      ".#prelink#") == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	  if (len >= sizeof (".#prelink#.XXXXXX") - 1
Packit 6c4009
	      && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX")
Packit 6c4009
			 + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
Packit 6c4009
	    continue;
Packit 6c4009
	}
Packit 6c4009
      len += strlen (entry->path) + 2;
Packit 6c4009
      if (len > file_name_len)
Packit 6c4009
	{
Packit 6c4009
	  file_name_len = len;
Packit 6c4009
	  file_name = alloca (file_name_len);
Packit 6c4009
	  if (!opt_chroot)
Packit 6c4009
	    real_file_name = file_name;
Packit 6c4009
	}
Packit 6c4009
      sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
Packit 6c4009
      if (opt_chroot)
Packit 6c4009
	{
Packit 6c4009
	  len = strlen (dir_name) + strlen (direntry->d_name) + 2;
Packit 6c4009
	  if (len > real_file_name_len)
Packit 6c4009
	    {
Packit 6c4009
	      real_file_name_len = len;
Packit 6c4009
	      real_file_name = alloca (real_file_name_len);
Packit 6c4009
	    }
Packit 6c4009
	  sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      struct stat64 lstat_buf;
Packit 6c4009
      /* We optimize and try to do the lstat call only if needed.  */
Packit 6c4009
      if (direntry->d_type != DT_UNKNOWN)
Packit 6c4009
	lstat_buf.st_mode = DTTOIF (direntry->d_type);
Packit 6c4009
      else
Packit 6c4009
	if (__glibc_unlikely (lstat64 (real_file_name, &lstat_buf)))
Packit 6c4009
	  {
Packit 6c4009
	    error (0, errno, _("Cannot lstat %s"), file_name);
Packit 6c4009
	    continue;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
      struct stat64 stat_buf;
Packit Service ad495e
      bool is_dir;
Packit 6c4009
      int is_link = S_ISLNK (lstat_buf.st_mode);
Packit 6c4009
      if (is_link)
Packit 6c4009
	{
Packit 6c4009
	  /* In case of symlink, we check if the symlink refers to
Packit 6c4009
	     a directory. */
Packit 6c4009
	  char *target_name = real_file_name;
Packit 6c4009
	  if (opt_chroot)
Packit 6c4009
	    {
Packit 6c4009
	      target_name = chroot_canon (opt_chroot, file_name);
Packit 6c4009
	      if (target_name == NULL)
Packit 6c4009
		{
Packit 6c4009
		  if (strstr (file_name, ".so") == NULL)
Packit 6c4009
		    error (0, 0, _("Input file %s not found.\n"), file_name);
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  if (__glibc_unlikely (stat64 (target_name, &stat_buf)))
Packit 6c4009
	    {
Packit 6c4009
	      if (opt_verbose)
Packit 6c4009
		error (0, errno, _("Cannot stat %s"), file_name);
Packit 6c4009
Packit 6c4009
	      /* Remove stale symlinks.  */
Packit 6c4009
	      if (opt_link && strstr (direntry->d_name, ".so."))
Packit 6c4009
		unlink (real_file_name);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
	  is_dir = S_ISDIR (stat_buf.st_mode);
Packit 6c4009
Packit 6c4009
	  /* lstat_buf is later stored, update contents.  */
Packit 6c4009
	  lstat_buf.st_dev = stat_buf.st_dev;
Packit 6c4009
	  lstat_buf.st_ino = stat_buf.st_ino;
Packit 6c4009
	  lstat_buf.st_size = stat_buf.st_size;
Packit 6c4009
	  lstat_buf.st_ctime = stat_buf.st_ctime;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	is_dir = S_ISDIR (lstat_buf.st_mode);
Packit 6c4009
Packit Service ad495e
      /* No descending into subdirectories if this directory is a
Packit Service ad495e
	 glibc-hwcaps subdirectory (which are not recursive).  */
Packit Service ad495e
      if (entry->hwcaps == NULL
Packit Service ad495e
	  && is_dir && is_hwcap_platform (direntry->d_name))
Packit 6c4009
	{
Packit 6c4009
	  if (!is_link
Packit 6c4009
	      && direntry->d_type != DT_UNKNOWN
Packit 6c4009
	      && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
Packit 6c4009
	    {
Packit 6c4009
	      error (0, errno, _("Cannot lstat %s"), file_name);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit Service 2bfe73
Packit Service 2bfe73
	  /* Handle subdirectory later.  */
Packit Service 2bfe73
	  struct dir_entry *new_entry = new_sub_entry (entry, file_name,
Packit Service 2bfe73
						       &lstat_buf);
Packit 6c4009
	  add_single_dir (new_entry, 0);
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
      else if (!S_ISREG (lstat_buf.st_mode) && !is_link)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      char *real_name;
Packit 6c4009
      if (opt_chroot && is_link)
Packit 6c4009
	{
Packit 6c4009
	  real_name = chroot_canon (opt_chroot, file_name);
Packit 6c4009
	  if (real_name == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      if (strstr (file_name, ".so") == NULL)
Packit 6c4009
		error (0, 0, _("Input file %s not found.\n"), file_name);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	real_name = real_file_name;
Packit 6c4009
Packit 6c4009
      /* Call lstat64 if not done yet.  */
Packit 6c4009
      if (!is_link
Packit 6c4009
	  && direntry->d_type != DT_UNKNOWN
Packit 6c4009
	  && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
Packit 6c4009
	{
Packit 6c4009
	  error (0, errno, _("Cannot lstat %s"), file_name);
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* First search whether the auxiliary cache contains this
Packit 6c4009
	 library already and it's not changed.  */
Packit 6c4009
      char *soname;
Packit 6c4009
      unsigned int osversion;
Packit 6c4009
      if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
Packit 6c4009
	{
Packit 6c4009
	  if (process_file (real_name, file_name, direntry->d_name, &flag,
Packit 6c4009
			    &osversion, &soname, is_link, &lstat_buf))
Packit 6c4009
	    {
Packit 6c4009
	      if (real_name != real_file_name)
Packit 6c4009
		free (real_name);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
	  else if (opt_build_cache)
Packit 6c4009
	    add_to_aux_cache (&lstat_buf, flag, osversion, soname);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (soname == NULL)
Packit 6c4009
	soname = implicit_soname (direntry->d_name, flag);
Packit 6c4009
Packit 6c4009
      /* A link may just point to itself.  */
Packit 6c4009
      if (is_link)
Packit 6c4009
	{
Packit 6c4009
	  /* If the path the link points to isn't its soname or it is not
Packit 6c4009
	     the .so symlink for ld(1), we treat it as a normal file.
Packit 6c4009
Packit 6c4009
	     You should always do this:
Packit 6c4009
Packit 6c4009
		libfoo.so -> SONAME -> Arbitrary package-chosen name.
Packit 6c4009
Packit 6c4009
	     e.g. libfoo.so -> libfoo.so.1 -> libfooimp.so.9.99.
Packit 6c4009
	     Given a SONAME of libfoo.so.1.
Packit 6c4009
Packit 6c4009
	     You should *never* do this:
Packit 6c4009
Packit 6c4009
		libfoo.so -> libfooimp.so.9.99
Packit 6c4009
Packit 6c4009
	     If you do, and your SONAME is libfoo.so.1, then libfoo.so
Packit 6c4009
	     fails to point at the SONAME. In that case ldconfig may consider
Packit 6c4009
	     libfoo.so as another implementation of SONAME and will create
Packit 6c4009
	     symlinks against it causing problems when you try to upgrade
Packit 6c4009
	     or downgrade. The problems will arise because ldconfig will,
Packit 6c4009
	     depending on directory ordering, creat symlinks against libfoo.so
Packit 6c4009
	     e.g. libfoo.so.1.2 -> libfoo.so, but when libfoo.so is removed
Packit 6c4009
	     (typically by the removal of a development pacakge not required
Packit 6c4009
	     for the runtime) it will break the libfoo.so.1.2 symlink and the
Packit 6c4009
	     application will fail to start.  */
Packit 6c4009
	  const char *real_base_name = basename (real_file_name);
Packit 6c4009
Packit 6c4009
	  if (strcmp (real_base_name, soname) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      len = strlen (real_base_name);
Packit 6c4009
	      if (len < strlen (".so")
Packit 6c4009
		  || strcmp (real_base_name + len - strlen (".so"), ".so") != 0
Packit 6c4009
		  || strncmp (real_base_name, soname, len) != 0)
Packit 6c4009
		is_link = 0;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (real_name != real_file_name)
Packit 6c4009
	free (real_name);
Packit 6c4009
Packit 6c4009
      if (is_link)
Packit 6c4009
	{
Packit 6c4009
	  free (soname);
Packit 6c4009
	  soname = xstrdup (direntry->d_name);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (flag == FLAG_ELF
Packit 6c4009
	  && (entry->flag == FLAG_ELF_LIBC5
Packit 6c4009
	      || entry->flag == FLAG_ELF_LIBC6))
Packit 6c4009
	flag = entry->flag;
Packit 6c4009
Packit 6c4009
      /* Some sanity checks to print warnings.  */
Packit 6c4009
      if (opt_verbose)
Packit 6c4009
	{
Packit 6c4009
	  if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
Packit 6c4009
	      && entry->flag != FLAG_ANY)
Packit 6c4009
	    error (0, 0, _("libc5 library %s in wrong directory"), file_name);
Packit 6c4009
	  if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
Packit 6c4009
	      && entry->flag != FLAG_ANY)
Packit 6c4009
	    error (0, 0, _("libc6 library %s in wrong directory"), file_name);
Packit 6c4009
	  if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
Packit 6c4009
	      && entry->flag != FLAG_ANY)
Packit 6c4009
	    error (0, 0, _("libc4 library %s in wrong directory"), file_name);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Add library to list.  */
Packit 6c4009
      struct dlib_entry *dlib_ptr;
Packit 6c4009
      for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
Packit 6c4009
	{
Packit 6c4009
	  /* Is soname already in list?  */
Packit 6c4009
	  if (strcmp (dlib_ptr->soname, soname) == 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* Prefer a file to a link, otherwise check which one
Packit 6c4009
		 is newer.  */
Packit 6c4009
	      if ((!is_link && dlib_ptr->is_link)
Packit 6c4009
		  || (is_link == dlib_ptr->is_link
Packit 6c4009
		      && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
Packit 6c4009
		{
Packit 6c4009
		  /* It's newer - add it.  */
Packit 6c4009
		  /* Flag should be the same - sanity check.  */
Packit 6c4009
		  if (dlib_ptr->flag != flag)
Packit 6c4009
		    {
Packit 6c4009
		      if (dlib_ptr->flag == FLAG_ELF
Packit 6c4009
			  && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
Packit 6c4009
			dlib_ptr->flag = flag;
Packit 6c4009
		      else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
Packit 6c4009
				|| dlib_ptr->flag == FLAG_ELF_LIBC6)
Packit 6c4009
			       && flag == FLAG_ELF)
Packit 6c4009
			dlib_ptr->flag = flag;
Packit 6c4009
		      else
Packit 6c4009
			error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
Packit 6c4009
			       dlib_ptr->name, direntry->d_name,
Packit 6c4009
			       entry->path);
Packit 6c4009
		    }
Packit 6c4009
		  free (dlib_ptr->name);
Packit 6c4009
		  dlib_ptr->name = xstrdup (direntry->d_name);
Packit 6c4009
		  dlib_ptr->is_link = is_link;
Packit 6c4009
		  dlib_ptr->osversion = osversion;
Packit 6c4009
		}
Packit 6c4009
	      /* Don't add this library, abort loop.  */
Packit 6c4009
	      /* Also free soname, since it's dynamically allocated.  */
Packit 6c4009
	      free (soname);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      /* Add the library if it's not already in.  */
Packit 6c4009
      if (dlib_ptr == NULL)
Packit 6c4009
	{
Packit 6c4009
	  dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
Packit 6c4009
	  dlib_ptr->name = xstrdup (direntry->d_name);
Packit 6c4009
	  dlib_ptr->soname = soname;
Packit 6c4009
	  dlib_ptr->flag = flag;
Packit 6c4009
	  dlib_ptr->is_link = is_link;
Packit 6c4009
	  dlib_ptr->osversion = osversion;
Packit 6c4009
	  /* Add at head of list.  */
Packit 6c4009
	  dlib_ptr->next = dlibs;
Packit 6c4009
	  dlibs = dlib_ptr;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  closedir (dir);
Packit 6c4009
Packit 6c4009
  /* Now dlibs contains a list of all libs - add those to the cache
Packit 6c4009
     and created all symbolic links.  */
Packit 6c4009
  struct dlib_entry *dlib_ptr;
Packit 6c4009
  for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
Packit 6c4009
    {
Packit Service ad495e
      /* The cached file name is the soname for non-glibc-hwcaps
Packit Service ad495e
	 subdirectories (relying on symbolic links; this helps with
Packit Service ad495e
	 library updates that change the file name), and the actual
Packit Service ad495e
	 file for glibc-hwcaps subdirectories.  */
Packit Service ad495e
      const char *filename;
Packit Service ad495e
      if (entry->hwcaps == NULL)
Packit Service ad495e
	{
Packit Service ad495e
	  /* Don't create links to links.  */
Packit Service ad495e
	  if (dlib_ptr->is_link == 0)
Packit Service ad495e
	    create_links (dir_name, entry->path, dlib_ptr->name,
Packit Service ad495e
			  dlib_ptr->soname);
Packit Service ad495e
	  filename = dlib_ptr->soname;
Packit Service ad495e
	}
Packit Service ad495e
      else
Packit Service ad495e
	{
Packit Service ad495e
	  /* Do not create links in glibc-hwcaps subdirectories, but
Packit Service ad495e
	     still log the cache addition.  */
Packit Service ad495e
	  if (opt_verbose)
Packit Service ad495e
	    printf ("\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name);
Packit Service ad495e
	  filename = dlib_ptr->name;
Packit Service ad495e
	}
Packit 6c4009
      if (opt_build_cache)
Packit Service ad495e
	add_to_cache (entry->path, filename, dlib_ptr->soname,
Packit Service ad495e
		      dlib_ptr->flag, dlib_ptr->osversion,
Packit Service ad495e
		      hwcap, entry->hwcaps);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Free all resources.  */
Packit 6c4009
  while (dlibs)
Packit 6c4009
    {
Packit 6c4009
      dlib_ptr = dlibs;
Packit 6c4009
      free (dlib_ptr->soname);
Packit 6c4009
      free (dlib_ptr->name);
Packit 6c4009
      dlibs = dlibs->next;
Packit 6c4009
      free (dlib_ptr);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (opt_chroot && dir_name)
Packit 6c4009
    free (dir_name);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Search through all libraries.  */
Packit 6c4009
static void
Packit 6c4009
search_dirs (void)
Packit 6c4009
{
Packit 6c4009
  struct dir_entry *entry;
Packit 6c4009
Packit 6c4009
  for (entry = dir_entries; entry != NULL; entry = entry->next)
Packit 6c4009
    search_dir (entry);
Packit 6c4009
Packit 6c4009
  /* Free all allocated memory.  */
Packit 6c4009
  while (dir_entries)
Packit 6c4009
    {
Packit 6c4009
      entry = dir_entries;
Packit 6c4009
      dir_entries = dir_entries->next;
Packit 6c4009
      free (entry->path);
Packit 6c4009
      free (entry);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void parse_conf_include (const char *config_file, unsigned int lineno,
Packit 6c4009
				bool do_chroot, const char *pattern);
Packit 6c4009
Packit 6c4009
/* Parse configuration file.  */
Packit 6c4009
static void
Packit 6c4009
parse_conf (const char *filename, bool do_chroot)
Packit 6c4009
{
Packit 6c4009
  FILE *file = NULL;
Packit 6c4009
  char *line = NULL;
Packit 6c4009
  const char *canon;
Packit 6c4009
  size_t len = 0;
Packit 6c4009
  unsigned int lineno;
Packit 6c4009
Packit 6c4009
  if (do_chroot && opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      canon = chroot_canon (opt_chroot, filename);
Packit 6c4009
      if (canon)
Packit 6c4009
	file = fopen (canon, "r");
Packit 6c4009
      else
Packit 6c4009
	canon = filename;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      canon = filename;
Packit 6c4009
      file = fopen (filename, "r");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (file == NULL)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("\
Packit 6c4009
Warning: ignoring configuration file that cannot be opened: %s"),
Packit 6c4009
	     canon);
Packit 6c4009
      if (canon != filename)
Packit 6c4009
	free ((char *) canon);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* No threads use this stream.  */
Packit 6c4009
  __fsetlocking (file, FSETLOCKING_BYCALLER);
Packit 6c4009
Packit 6c4009
  if (canon != filename)
Packit 6c4009
    free ((char *) canon);
Packit 6c4009
Packit 6c4009
  lineno = 0;
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      ssize_t n = getline (&line, &len, file);
Packit 6c4009
      if (n < 0)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      ++lineno;
Packit 6c4009
      if (line[n - 1] == '\n')
Packit 6c4009
	line[n - 1] = '\0';
Packit 6c4009
Packit 6c4009
      /* Because the file format does not know any form of quoting we
Packit 6c4009
	 can search forward for the next '#' character and if found
Packit 6c4009
	 make it terminating the line.  */
Packit 6c4009
      *strchrnul (line, '#') = '\0';
Packit 6c4009
Packit 6c4009
      /* Remove leading whitespace.  NUL is no whitespace character.  */
Packit 6c4009
      char *cp = line;
Packit 6c4009
      while (isspace (*cp))
Packit 6c4009
	++cp;
Packit 6c4009
Packit 6c4009
      /* If the line is blank it is ignored.  */
Packit 6c4009
      if (cp[0] == '\0')
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      if (!strncmp (cp, "include", 7) && isblank (cp[7]))
Packit 6c4009
	{
Packit 6c4009
	  char *dir;
Packit 6c4009
	  cp += 8;
Packit 6c4009
	  while ((dir = strsep (&cp, " \t")) != NULL)
Packit 6c4009
	    if (dir[0] != '\0')
Packit 6c4009
	      parse_conf_include (filename, lineno, do_chroot, dir);
Packit 6c4009
	}
Packit 6c4009
      else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
Packit Service c1780e
	error (0, 0, _("%s:%u: hwcap directive ignored"), filename, lineno);
Packit 6c4009
      else
Packit Service 63e04b
	add_dir_1 (cp, filename, lineno);
Packit 6c4009
    }
Packit 6c4009
  while (!feof_unlocked (file));
Packit 6c4009
Packit 6c4009
  /* Free buffer and close file.  */
Packit 6c4009
  free (line);
Packit 6c4009
  fclose (file);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Handle one word in an `include' line, a glob pattern of additional
Packit 6c4009
   config files to read.  */
Packit 6c4009
static void
Packit 6c4009
parse_conf_include (const char *config_file, unsigned int lineno,
Packit 6c4009
		    bool do_chroot, const char *pattern)
Packit 6c4009
{
Packit 6c4009
  if (opt_chroot && pattern[0] != '/')
Packit 6c4009
    error (EXIT_FAILURE, 0,
Packit 6c4009
	   _("need absolute file name for configuration file when using -r"));
Packit 6c4009
Packit 6c4009
  char *copy = NULL;
Packit 6c4009
  if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
Packit 6c4009
    {
Packit 6c4009
      if (asprintf (&copy, "%s/%s", dirname (strdupa (config_file)),
Packit 6c4009
		    pattern) < 0)
Packit 6c4009
	error (EXIT_FAILURE, 0, _("memory exhausted"));
Packit 6c4009
      pattern = copy;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  glob64_t gl;
Packit 6c4009
  int result;
Packit 6c4009
  if (do_chroot && opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      char *canon = chroot_canon (opt_chroot, pattern);
Packit 6c4009
      if (canon == NULL)
Packit 6c4009
	return;
Packit 6c4009
      result = glob64 (canon, 0, NULL, &gl);
Packit 6c4009
      free (canon);
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    result = glob64 (pattern, 0, NULL, &gl);
Packit 6c4009
Packit 6c4009
  switch (result)
Packit 6c4009
    {
Packit 6c4009
    case 0:
Packit 6c4009
      for (size_t i = 0; i < gl.gl_pathc; ++i)
Packit 6c4009
	parse_conf (gl.gl_pathv[i], false);
Packit 6c4009
      globfree64 (&gl);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case GLOB_NOMATCH:
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case GLOB_NOSPACE:
Packit 6c4009
      errno = ENOMEM;
Packit Service cbf6e0
      /* Fall through.  */
Packit 6c4009
    case GLOB_ABORTED:
Packit 6c4009
      if (opt_verbose)
Packit 6c4009
	error (0, errno, _("%s:%u: cannot read directory %s"),
Packit 6c4009
	       config_file, lineno, pattern);
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      abort ();
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  free (copy);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Honour LD_HWCAP_MASK.  */
Packit 6c4009
static void
Packit 6c4009
set_hwcap (void)
Packit 6c4009
{
Packit 6c4009
  char *mask = getenv ("LD_HWCAP_MASK");
Packit 6c4009
Packit 6c4009
  if (mask)
Packit 6c4009
    hwcap_mask = strtoul (mask, NULL, 0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (int argc, char **argv)
Packit 6c4009
{
Packit 6c4009
  /* Set locale via LC_ALL.  */
Packit 6c4009
  setlocale (LC_ALL, "");
Packit 6c4009
Packit 6c4009
  /* But keep the C collation.  That way `include' directives using
Packit 6c4009
     globbing patterns are processed in a locale-independent order.  */
Packit 6c4009
  setlocale (LC_COLLATE, "C");
Packit 6c4009
Packit 6c4009
  /* Set the text message domain.  */
Packit 6c4009
  textdomain (_libc_intl_domainname);
Packit 6c4009
Packit 6c4009
  /* Parse and process arguments.  */
Packit 6c4009
  int remaining;
Packit 6c4009
  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
Packit 6c4009
Packit 6c4009
  /* Remaining arguments are additional directories if opt_manual_link
Packit 6c4009
     is not set.  */
Packit 6c4009
  if (remaining != argc && !opt_manual_link)
Packit 6c4009
    {
Packit 6c4009
      int i;
Packit 6c4009
      for (i = remaining; i < argc; ++i)
Packit 6c4009
	if (opt_build_cache && argv[i][0] != '/')
Packit 6c4009
	  error (EXIT_FAILURE, 0,
Packit 6c4009
		 _("relative path `%s' used to build cache"),
Packit 6c4009
		 argv[i]);
Packit 6c4009
	else
Packit Service 63e04b
	  add_dir_1 (argv[i], "<cmdline>", 0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  set_hwcap ();
Packit 6c4009
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      /* Normalize the path a bit, we might need it for printing later.  */
Packit 6c4009
      char *endp = rawmemchr (opt_chroot, '\0');
Packit 6c4009
      while (endp > opt_chroot && endp[-1] == '/')
Packit 6c4009
	--endp;
Packit 6c4009
      *endp = '\0';
Packit 6c4009
      if (endp == opt_chroot)
Packit 6c4009
	opt_chroot = NULL;
Packit 6c4009
Packit 6c4009
      if (opt_chroot)
Packit 6c4009
	{
Packit 6c4009
	  /* It is faster to use chroot if we can.  */
Packit 6c4009
	  if (!chroot (opt_chroot))
Packit 6c4009
	    {
Packit 6c4009
	      if (chdir ("/"))
Packit 6c4009
		error (EXIT_FAILURE, errno, _("Can't chdir to /"));
Packit 6c4009
	      opt_chroot = NULL;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (cache_file == NULL)
Packit 6c4009
    {
Packit 6c4009
      cache_file = alloca (strlen (LD_SO_CACHE) + 1);
Packit 6c4009
      strcpy (cache_file, LD_SO_CACHE);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (config_file == NULL)
Packit 6c4009
    config_file = LD_SO_CONF;
Packit 6c4009
Packit 6c4009
  if (opt_print_cache)
Packit 6c4009
    {
Packit 6c4009
      if (opt_chroot)
Packit 6c4009
	{
Packit 6c4009
	  char *p = chroot_canon (opt_chroot, cache_file);
Packit 6c4009
	  if (p == NULL)
Packit 6c4009
	    error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
Packit 6c4009
		   cache_file);
Packit 6c4009
	  cache_file = p;
Packit 6c4009
	}
Packit 6c4009
      print_cache (cache_file);
Packit 6c4009
      if (opt_chroot)
Packit 6c4009
	free (cache_file);
Packit 6c4009
      exit (0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    {
Packit 6c4009
      /* Canonicalize the directory name of cache_file, not cache_file,
Packit 6c4009
	 because we'll rename a temporary cache file to it.  */
Packit 6c4009
      char *p = strrchr (cache_file, '/');
Packit 6c4009
      char *canon = chroot_canon (opt_chroot,
Packit 6c4009
				  p ? (*p = '\0', cache_file) : "/");
Packit 6c4009
Packit 6c4009
      if (canon == NULL)
Packit 6c4009
	error (EXIT_FAILURE, errno,
Packit 6c4009
	       _("Can't open cache file directory %s\n"),
Packit 6c4009
	       p ? cache_file : "/");
Packit 6c4009
Packit 6c4009
      if (p)
Packit 6c4009
	++p;
Packit 6c4009
      else
Packit 6c4009
	p = cache_file;
Packit 6c4009
Packit 6c4009
      cache_file = alloca (strlen (canon) + strlen (p) + 2);
Packit 6c4009
      sprintf (cache_file, "%s/%s", canon, p);
Packit 6c4009
      free (canon);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (opt_manual_link)
Packit 6c4009
    {
Packit 6c4009
      /* Link all given libraries manually.  */
Packit 6c4009
      int i;
Packit 6c4009
Packit 6c4009
      for (i = remaining; i < argc; ++i)
Packit 6c4009
	manual_link (argv[i]);
Packit 6c4009
Packit 6c4009
      exit (0);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
Packit 6c4009
  if (opt_build_cache)
Packit 6c4009
    init_cache ();
Packit 6c4009
Packit 6c4009
  if (!opt_only_cline)
Packit 6c4009
    {
Packit 6c4009
      parse_conf (config_file, true);
Packit 6c4009
Packit 6c4009
      /* Always add the standard search paths.  */
Packit 6c4009
      add_system_dir (SLIBDIR);
Packit 6c4009
      if (strcmp (SLIBDIR, LIBDIR))
Packit 6c4009
	add_system_dir (LIBDIR);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
Packit 6c4009
  if (opt_chroot)
Packit 6c4009
    aux_cache_file = chroot_canon (opt_chroot, aux_cache_file);
Packit 6c4009
Packit 6c4009
  if (! opt_ignore_aux_cache && aux_cache_file)
Packit 6c4009
    load_aux_cache (aux_cache_file);
Packit 6c4009
  else
Packit 6c4009
    init_aux_cache ();
Packit 6c4009
Packit 6c4009
  search_dirs ();
Packit 6c4009
Packit 6c4009
  if (opt_build_cache)
Packit 6c4009
    {
Packit 6c4009
      save_cache (cache_file);
Packit 6c4009
      if (aux_cache_file)
Packit 6c4009
	save_aux_cache (aux_cache_file);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}