Blame elf/ldconfig.c

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