Back to index

glibc  2.9
Classes | Defines | Functions | Variables
ldconfig.c File Reference
#include <alloca.h>
#include <argp.h>
#include <dirent.h>
#include <elf.h>
#include <error.h>
#include <errno.h>
#include <inttypes.h>
#include <libintl.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glob.h>
#include <libgen.h>
#include <ldconfig.h>
#include <dl-cache.h>
#include <dl-procinfo.h>
#include <version.h>
#include <dl-procinfo.c>

Go to the source code of this file.

Classes

struct  dir_entry
struct  dlib_entry

Defines

#define PROCINFO_CLASS   static
#define _DL_FIRST_EXTRA   _DL_HWCAP_COUNT
#define LD_SO_CONF   SYSCONFDIR "/ld.so.conf"
#define PACKAGE   _libc_intl_domainname
#define PROCINFO_CLASS   static

Functions

static void print_version (FILE *stream, struct argp_state *state)
static error_t parse_opt (int key, char *arg, struct argp_state *state)
static int is_hwcap_platform (const char *name)
static uint64_t path_hwcap (const char *path)
static void add_single_dir (struct dir_entry *entry, int verbose)
static void add_dir (const char *line)
static int chroot_stat (const char *real_path, const char *path, struct stat64 *st)
static void create_links (const char *real_path, const char *path, const char *libname, const char *soname)
static void manual_link (char *library)
static void search_dir (const struct dir_entry *entry)
static void search_dirs (void)
static void parse_conf_include (const char *config_file, unsigned int lineno, bool do_chroot, const char *pattern)
static void parse_conf (const char *filename, bool do_chroot)
static void set_hwcap (void)
int main (int argc, char **argv)

Variables

struct {
const char * name
int flag
lib_types []
static struct dir_entrydir_entries
static int opt_print_cache
int opt_verbose
int opt_format = 1
static int opt_build_cache = 1
static int opt_link = 1
static int opt_only_cline
static char * opt_chroot
static int opt_manual_link
static int opt_ignore_aux_cache
static char * cache_file
static const char * config_file
static unsigned long int hwcap_mask = HWCAP_IMPORTANT
static const char * hwcap_extra [64-_DL_FIRST_EXTRA]
void(* argp_program_version_hook )(FILE *, struct argp_state *) = print_version
static struct argp_option []
static const char doc [] = N_("Configure Dynamic Linker Run Time Bindings.")
static struct argp

Class Documentation

struct dir_entry

Definition at line 76 of file ldconfig.c.

Collaboration diagram for dir_entry:
Class Members
dev_t dev
int flag
ino64_t ino
struct dir_entry * next
char * path
struct dlib_entry

Definition at line 626 of file ldconfig.c.

Collaboration diagram for dlib_entry:
Class Members
int flag
int is_link
char * name
struct dlib_entry * next
unsigned int osversion
char * soname

Define Documentation

Definition at line 50 of file ldconfig.c.

#define LD_SO_CONF   SYSCONFDIR "/ld.so.conf"

Definition at line 54 of file ldconfig.c.

Definition at line 60 of file ldconfig.c.

#define PROCINFO_CLASS   static

Definition at line 152 of file ldconfig.c.

#define PROCINFO_CLASS   static

Definition at line 152 of file ldconfig.c.


Function Documentation

static void add_dir ( const char *  line) [static]

Definition at line 338 of file ldconfig.c.

{
  unsigned int i;
  struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
  entry->next = NULL;

  /* Search for an '=' sign.  */
  entry->path = xstrdup (line);
  char *equal_sign = strchr (entry->path, '=');
  if (equal_sign)
    {
      *equal_sign = '\0';
      ++equal_sign;
      entry->flag = FLAG_ANY;
      for (i = 0; i < sizeof (lib_types) / sizeof (lib_types[0]); ++i)
       if (strcmp (equal_sign, lib_types[i].name) == 0)
         {
           entry->flag = lib_types[i].flag;
           break;
         }
      if (entry->flag == FLAG_ANY)
       error (0, 0, _("%s is not a known library type"), equal_sign);
    }
  else
    {
      entry->flag = FLAG_ANY;
    }

  /* Canonify path: for now only remove leading and trailing
     whitespace and the trailing slashes slashes.  */
  i = strlen (entry->path) - 1;

  while (isspace (entry->path[i]) && i > 0)
    entry->path[i--] = '\0';

  while (entry->path[i] == '/' && i > 0)
    entry->path[i--] = '\0';

  char *path = entry->path;
  if (opt_chroot)
    path = chroot_canon (opt_chroot, path);

  struct stat64 stat_buf;
  if (path == NULL || stat64 (path, &stat_buf))
    {
      if (opt_verbose)
       error (0, errno, _("Can't stat %s"), entry->path);
      free (entry->path);
      free (entry);
    }
  else
    {
      entry->ino = stat_buf.st_ino;
      entry->dev = stat_buf.st_dev;

      add_single_dir (entry, 1);
    }

  if (opt_chroot)
    free (path);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_single_dir ( struct dir_entry entry,
int  verbose 
) [static]

Definition at line 307 of file ldconfig.c.

{
  struct dir_entry *ptr, *prev;

  ptr = dir_entries;
  prev = ptr;
  while (ptr != NULL)
    {
      /* Check for duplicates.  */
      if (ptr->ino == entry->ino && ptr->dev == entry->dev)
       {
         if (opt_verbose && verbose)
           error (0, 0, _("Path `%s' given more than once"), entry->path);
         /* Use the newer information.  */
         ptr->flag = entry->flag;
         free (entry->path);
         free (entry);
         break;
       }
      prev = ptr;
      ptr = ptr->next;
    }
  /* Is this the first entry?  */
  if (ptr == NULL && dir_entries == NULL)
    dir_entries = entry;
  else if (ptr == NULL)
    prev->next = entry;
}

Here is the caller graph for this function:

static int chroot_stat ( const char *  real_path,
const char *  path,
struct stat64 st 
) [static]

Definition at line 402 of file ldconfig.c.

{
  int ret;
  char *canon_path;

  if (!opt_chroot)
    return stat64 (real_path, st);

  ret = lstat64 (real_path, st);
  if (ret || !S_ISLNK (st->st_mode))
    return ret;

  canon_path = chroot_canon (opt_chroot, path);
  if (canon_path == NULL)
    return -1;

  ret = stat64 (canon_path, st);
  free (canon_path);
  return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void create_links ( const char *  real_path,
const char *  path,
const char *  libname,
const char *  soname 
) [static]

Definition at line 425 of file ldconfig.c.

{
  char *full_libname, *full_soname;
  char *real_full_libname, *real_full_soname;
  struct stat64 stat_lib, stat_so, lstat_so;
  int do_link = 1;
  int do_remove = 1;
  /* XXX: The logics in this function should be simplified.  */

  /* Get complete path.  */
  full_libname = alloca (strlen (path) + strlen (libname) + 2);
  full_soname = alloca (strlen (path) + strlen (soname) + 2);
  sprintf (full_libname, "%s/%s", path, libname);
  sprintf (full_soname, "%s/%s", path, soname);
  if (opt_chroot)
    {
      real_full_libname = alloca (strlen (real_path) + strlen (libname) + 2);
      real_full_soname = alloca (strlen (real_path) + strlen (soname) + 2);
      sprintf (real_full_libname, "%s/%s", real_path, libname);
      sprintf (real_full_soname, "%s/%s", real_path, soname);
    }
  else
    {
      real_full_libname = full_libname;
      real_full_soname = full_soname;
    }

  /* Does soname already exist and point to the right library?  */
  if (chroot_stat (real_full_soname, full_soname, &stat_so) == 0)
    {
      if (chroot_stat (real_full_libname, full_libname, &stat_lib))
       {
         error (0, 0, _("Can't stat %s\n"), full_libname);
         return;
       }
      if (stat_lib.st_dev == stat_so.st_dev
         && stat_lib.st_ino == stat_so.st_ino)
       /* Link is already correct.  */
       do_link = 0;
      else if (lstat64 (full_soname, &lstat_so) == 0
              && !S_ISLNK (lstat_so.st_mode))
       {
         error (0, 0, _("%s is not a symbolic link\n"), full_soname);
         do_link = 0;
         do_remove = 0;
       }
    }
  else if (lstat64 (real_full_soname, &lstat_so) != 0
          || !S_ISLNK (lstat_so.st_mode))
    /* Unless it is a stale symlink, there is no need to remove.  */
    do_remove = 0;

  if (opt_verbose)
    printf ("\t%s -> %s", soname, libname);

  if (do_link && opt_link)
    {
      /* Remove old link.  */
      if (do_remove)
       if (unlink (real_full_soname))
         {
           error (0, 0, _("Can't unlink %s"), full_soname);
           do_link = 0;
         }
      /* Create symbolic link.  */
      if (do_link && symlink (libname, real_full_soname))
       {
         error (0, 0, _("Can't link %s to %s"), full_soname, libname);
         do_link = 0;
       }
      if (opt_verbose)
       {
         if (do_link)
           fputs (_(" (changed)\n"), stdout);
         else
           fputs (_(" (SKIPPED)\n"), stdout);
       }
    }
  else if (opt_verbose)
    fputs ("\n", stdout);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int is_hwcap_platform ( const char *  name) [static]

Definition at line 170 of file ldconfig.c.

{
  int hwcap_idx = _dl_string_hwcap (name);

  if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
    return 1;

  hwcap_idx = _dl_string_platform (name);
  if (hwcap_idx != -1)
    return 1;

  for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
    if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
       && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
      return 1;

  return 0;
}

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 1202 of file ldconfig.c.

{
  /* Set locale via LC_ALL.  */
  setlocale (LC_ALL, "");

  /* Set the text message domain.  */
  textdomain (_libc_intl_domainname);

  /* Parse and process arguments.  */
  int remaining;
  argp_parse (&argp, argc, argv, 0, &remaining, NULL);

  /* Remaining arguments are additional directories if opt_manual_link
     is not set.  */
  if (remaining != argc && !opt_manual_link)
    {
      int i;
      for (i = remaining; i < argc; ++i)
       if (opt_build_cache && argv[i][0] != '/')
         error (EXIT_FAILURE, 0,
               _("relative path `%s' used to build cache"),
               argv[i]);
       else
         add_dir (argv[i]);
    }

  hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls";

  set_hwcap ();

  if (opt_chroot)
    {
      /* Normalize the path a bit, we might need it for printing later.  */
      char *endp = rawmemchr (opt_chroot, '\0');
      while (endp > opt_chroot && endp[-1] == '/')
       --endp;
      *endp = '\0';
      if (endp == opt_chroot)
       opt_chroot = NULL;

      if (opt_chroot)
       {
         /* It is faster to use chroot if we can.  */
         if (!chroot (opt_chroot))
           {
             if (chdir ("/"))
              error (EXIT_FAILURE, errno, _("Can't chdir to /"));
             opt_chroot = NULL;
           }
       }
    }

  if (cache_file == NULL)
    {
      cache_file = alloca (strlen (LD_SO_CACHE) + 1);
      strcpy (cache_file, LD_SO_CACHE);
    }

  if (config_file == NULL)
    config_file = LD_SO_CONF;

  if (opt_print_cache)
    {
      if (opt_chroot)
       {
         char *p = chroot_canon (opt_chroot, cache_file);
         if (p == NULL)
           error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"),
                 cache_file);
         cache_file = p;
       }
      print_cache (cache_file);
      if (opt_chroot)
       free (cache_file);
      exit (0);
    }

  if (opt_chroot)
    {
      /* Canonicalize the directory name of cache_file, not cache_file,
        because we'll rename a temporary cache file to it.  */
      char *p = strrchr (cache_file, '/');
      char *canon = chroot_canon (opt_chroot,
                              p ? (*p = '\0', cache_file) : "/");

      if (canon == NULL)
       {
         error (EXIT_FAILURE, errno,
               _("Can't open cache file directory %s\n"),
               p ? cache_file : "/");
       }

      if (p)
       ++p;
      else
       p = cache_file;

      cache_file = alloca (strlen (canon) + strlen (p) + 2);
      sprintf (cache_file, "%s/%s", canon, p);
      free (canon);
    }

  if (opt_manual_link)
    {
      /* Link all given libraries manually.  */
      int i;

      for (i = remaining; i < argc; ++i)
       manual_link (argv[i]);

      exit (0);
    }


  if (opt_build_cache)
    init_cache ();

  if (!opt_only_cline)
    {
      parse_conf (config_file, true);

      /* Always add the standard search paths.  */
      add_system_dir (SLIBDIR);
      if (strcmp (SLIBDIR, LIBDIR))
       add_system_dir (LIBDIR);
    }

  if (! opt_ignore_aux_cache)
    load_aux_cache (_PATH_LDCONFIG_AUX_CACHE);
  else
    init_aux_cache ();

  search_dirs ();

  if (opt_build_cache)
    {
      save_cache (cache_file);
      save_aux_cache (_PATH_LDCONFIG_AUX_CACHE);
    }

  return 0;
}

Here is the call graph for this function:

static void manual_link ( char *  library) [static]

Definition at line 510 of file ldconfig.c.

{
  char *path;
  char *real_path;
  char *real_library;
  char *libname;
  char *soname;
  struct stat64 stat_buf;
  int flag;
  unsigned int osversion;

  /* Prepare arguments for create_links call.  Split library name in
     directory and filename first.  Since path is allocated, we've got
     to be careful to free at the end.  */
  path = xstrdup (library);
  libname = strrchr (path, '/');

  if (libname)
    {
      /* Successfully split names.  Check if path is just "/" to avoid
        an empty path.  */
      if (libname == path)
       {
         libname = library + 1;
         path = xrealloc (path, 2);
         strcpy (path, "/");
       }
      else
       {
         *libname = '\0';
         ++libname;
       }
    }
  else
    {
      /* There's no path, construct one. */
      libname = library;
      path = xrealloc (path, 2);
      strcpy (path, ".");
    }

  if (opt_chroot)
    {
      real_path = chroot_canon (opt_chroot, path);
      if (real_path == NULL)
       {
         error (0, errno, _("Can't find %s"), path);
         free (path);
         return;
       }
      real_library = alloca (strlen (real_path) + strlen (libname) + 2);
      sprintf (real_library, "%s/%s", real_path, libname);
    }
  else
    {
      real_path = path;
      real_library = library;
    }

  /* Do some sanity checks first.  */
  if (lstat64 (real_library, &stat_buf))
    {
      error (0, errno, _("Cannot lstat %s"), library);
      free (path);
      return;
    }
  /* We don't want links here!  */
  else if (!S_ISREG (stat_buf.st_mode))
    {
      error (0, 0, _("Ignored file %s since it is not a regular file."),
            library);
      free (path);
      return;
    }

  if (process_file (real_library, library, libname, &flag, &osversion,
                  &soname, 0, &stat_buf))
    {
      error (0, 0, _("No link created since soname could not be found for %s"),
            library);
      free (path);
      return;
    }
  if (soname == NULL)
    soname = implicit_soname (libname, flag);
  create_links (real_path, path, libname, soname);
  free (soname);
  free (path);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void parse_conf ( const char *  filename,
bool  do_chroot 
) [static]

Definition at line 1007 of file ldconfig.c.

{
  FILE *file = NULL;
  char *line = NULL;
  const char *canon;
  size_t len = 0;
  unsigned int lineno;

  if (do_chroot && opt_chroot)
    {
      canon = chroot_canon (opt_chroot, filename);
      if (canon)
       file = fopen (canon, "r");
      else
       canon = filename;
    }
  else
    {
      canon = filename;
      file = fopen (filename, "r");
    }

  if (file == NULL)
    {
      error (0, errno, _("Can't open configuration file %s"), canon);
      if (canon != filename)
       free ((char *) canon);
      return;
    }

  /* No threads use this stream.  */
  __fsetlocking (file, FSETLOCKING_BYCALLER);

  if (canon != filename)
    free ((char *) canon);

  lineno = 0;
  do
    {
      ssize_t n = getline (&line, &len, file);
      if (n < 0)
       break;

      ++lineno;
      if (line[n - 1] == '\n')
       line[n - 1] = '\0';

      /* Because the file format does not know any form of quoting we
        can search forward for the next '#' character and if found
        make it terminating the line.  */
      *strchrnul (line, '#') = '\0';

      /* Remove leading whitespace.  NUL is no whitespace character.  */
      char *cp = line;
      while (isspace (*cp))
       ++cp;

      /* If the line is blank it is ignored.  */
      if (cp[0] == '\0')
       continue;

      if (!strncmp (cp, "include", 7) && isblank (cp[7]))
       {
         char *dir;
         cp += 8;
         while ((dir = strsep (&cp, " \t")) != NULL)
           if (dir[0] != '\0')
             parse_conf_include (filename, lineno, do_chroot, dir);
       }
      else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
       {
         cp += 6;
         char *p, *name = NULL;
         unsigned long int n = strtoul (cp, &cp, 0);
         if (cp != NULL && isblank (*cp))
           while ((p = strsep (&cp, " \t")) != NULL)
             if (p[0] != '\0')
              {
                if (name == NULL)
                  name = p;
                else
                  {
                    name = NULL;
                    break;
                  }
              }
         if (name == NULL)
           {
             error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"),
                   filename, lineno);
             break;
           }
         if (n >= (64 - _DL_FIRST_EXTRA))
           error (EXIT_FAILURE, 0,
                 _("%s:%u: hwcap index %lu above maximum %u"),
                 filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1);
         if (hwcap_extra[n] == NULL)
           {
             for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h)
              if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h]))
                error (EXIT_FAILURE, 0,
                      _("%s:%u: hwcap index %lu already defined as %s"),
                      filename, lineno, h, name);
             hwcap_extra[n] = xstrdup (name);
           }
         else
           {
             if (strcmp (name, hwcap_extra[n]))
              error (EXIT_FAILURE, 0,
                     _("%s:%u: hwcap index %lu already defined as %s"),
                     filename, lineno, n, hwcap_extra[n]);
             if (opt_verbose)
              error (0, 0, _("%s:%u: duplicate hwcap %lu %s"),
                     filename, lineno, n, name);
           }
       }
      else
       add_dir (cp);
    }
  while (!feof_unlocked (file));

  /* Free buffer and close file.  */
  free (line);
  fclose (file);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void parse_conf_include ( const char *  config_file,
unsigned int  lineno,
bool  do_chroot,
const char *  pattern 
) [static]

Definition at line 1136 of file ldconfig.c.

{
  if (opt_chroot && pattern[0] != '/')
    error (EXIT_FAILURE, 0,
          _("need absolute file name for configuration file when using -r"));

  char *copy = NULL;
  if (pattern[0] != '/' && strchr (config_file, '/') != NULL)
    {
      if (asprintf (&copy, "%s/%s", dirname (strdupa (config_file)),
                  pattern) < 0)
       error (EXIT_FAILURE, 0, _("memory exhausted"));
      pattern = copy;
    }

  glob64_t gl;
  int result;
  if (do_chroot && opt_chroot)
    {
      char *canon = chroot_canon (opt_chroot, pattern);
      result = glob64 (canon ?: pattern, 0, NULL, &gl);
      free (canon);
    }
  else
    result = glob64 (pattern, 0, NULL, &gl);

  switch (result)
    {
    case 0:
      for (size_t i = 0; i < gl.gl_pathc; ++i)
       parse_conf (gl.gl_pathv[i], false);
      globfree64 (&gl);
      break;

    case GLOB_NOMATCH:
      break;

    case GLOB_NOSPACE:
      errno = ENOMEM;
    case GLOB_ABORTED:
      if (opt_verbose)
       error (0, errno, _("%s:%u: cannot read directory %s"),
              config_file, lineno, pattern);
      break;

    default:
      abort ();
      break;
    }

  free (copy);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static error_t parse_opt ( int  key,
char *  arg,
struct argp_state state 
) [static]

Definition at line 239 of file ldconfig.c.

{
  switch (key)
    {
    case 'C':
      cache_file = arg;
      /* Ignore auxiliary cache since we use non-standard cache.  */
      opt_ignore_aux_cache = 1;
      break;
    case 'f':
      config_file = arg;
      break;
    case 'i':
      opt_ignore_aux_cache = 1;
      break;
    case 'l':
      opt_manual_link = 1;
      break;
    case 'N':
      opt_build_cache = 0;
      break;
    case 'n':
      opt_build_cache = 0;
      opt_only_cline = 1;
      break;
    case 'p':
      opt_print_cache = 1;
      break;
    case 'r':
      opt_chroot = arg;
      break;
    case 'v':
      opt_verbose = 1;
      break;
    case 'X':
      opt_link = 0;
      break;
    case 'c':
      if (strcmp (arg, "old") == 0)
       opt_format = 0;
      else if (strcmp (arg, "compat") == 0)
       opt_format = 1;
      else if (strcmp (arg, "new") == 0)
       opt_format = 2;
      break;
    default:
      return ARGP_ERR_UNKNOWN;
    }

  return 0;
}
static uint64_t path_hwcap ( const char *  path) [static]

Definition at line 191 of file ldconfig.c.

{
  char *str = xstrdup (path);
  char *ptr;
  uint64_t hwcap = 0;
  uint64_t h;

  size_t len;

  len = strlen (str);
  if (str[len] == '/')
    str[len] = '\0';

  /* Search pathname from the end and check for hwcap strings.  */
  for (;;)
    {
      ptr = strrchr (str, '/');

      if (ptr == NULL)
       break;

      h = _dl_string_hwcap (ptr + 1);

      if (h == (uint64_t) -1)
       {
         h = _dl_string_platform (ptr + 1);
         if (h == (uint64_t) -1)
           {
             for (h = _DL_FIRST_EXTRA; h < 64; ++h)
              if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
                  && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
                break;
             if (h == 64)
              break;
           }
       }
      hwcap += 1ULL << h;

      /* Search the next part of the path.  */
      *ptr = '\0';
    }

  free (str);
  return hwcap;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void print_version ( FILE stream,
struct argp_state state 
) [static]

Definition at line 293 of file ldconfig.c.

{
  fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
  fprintf (stream, gettext ("\
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions.  There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), "2008");
  fprintf (stream, gettext ("Written by %s.\n"),
          "Andreas Jaeger");
}

Here is the call graph for this function:

static void search_dir ( const struct dir_entry entry) [static]

Definition at line 638 of file ldconfig.c.

{
  uint64_t hwcap = path_hwcap (entry->path);
  if (opt_verbose)
    {
      if (hwcap != 0)
       printf ("%s: (hwcap: %#.16" PRIx64 ")\n", entry->path, hwcap);
      else
       printf ("%s:\n", entry->path);
    }

  char *dir_name;
  char *real_file_name;
  size_t real_file_name_len;
  size_t file_name_len = PATH_MAX;
  char *file_name = alloca (file_name_len);
  if (opt_chroot)
    {
      dir_name = chroot_canon (opt_chroot, entry->path);
      real_file_name_len = PATH_MAX;
      real_file_name = alloca (real_file_name_len);
    }
  else
    {
      dir_name = entry->path;
      real_file_name_len = 0;
      real_file_name = file_name;
    }

  DIR *dir;
  if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
    {
      if (opt_verbose)
       error (0, errno, _("Can't open directory %s"), entry->path);
      if (opt_chroot && dir_name)
       free (dir_name);
      return;
    }

  struct dirent64 *direntry;
  struct dlib_entry *dlibs = NULL;
  while ((direntry = readdir64 (dir)) != NULL)
    {
      int flag;
#ifdef _DIRENT_HAVE_D_TYPE
      /* We only look at links and regular files.  */
      if (direntry->d_type != DT_UNKNOWN
         && direntry->d_type != DT_LNK
         && direntry->d_type != DT_REG
         && direntry->d_type != DT_DIR)
       continue;
#endif /* _DIRENT_HAVE_D_TYPE  */
      /* Does this file look like a shared library or is it a hwcap
        subdirectory?  The dynamic linker is also considered as
        shared library.  */
      if (((strncmp (direntry->d_name, "lib", 3) != 0
           && strncmp (direntry->d_name, "ld-", 3) != 0)
          || strstr (direntry->d_name, ".so") == NULL)
         && (
#ifdef _DIRENT_HAVE_D_TYPE
             direntry->d_type == DT_REG ||
#endif
             !is_hwcap_platform (direntry->d_name)))
       continue;

      size_t len = strlen (direntry->d_name);
      /* Skip temporary files created by the prelink program.  Files with
        names like these are never really DSOs we want to look at.  */
      if (len >= sizeof (".#prelink#") - 1)
       {
         if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1,
                    ".#prelink#") == 0)
           continue;
         if (len >= sizeof (".#prelink#.XXXXXX") - 1
             && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX")
                      + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
           continue;
       }
      len += strlen (entry->path) + 2;
      if (len > file_name_len)
       {
         file_name_len = len;
         file_name = alloca (file_name_len);
         if (!opt_chroot)
           real_file_name = file_name;
       }
      sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
      if (opt_chroot)
       {
         len = strlen (dir_name) + strlen (direntry->d_name) + 2;
         if (len > real_file_name_len)
           {
             real_file_name_len = len;
             real_file_name = alloca (real_file_name_len);
           }
         sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
       }

      struct stat64 lstat_buf;
#ifdef _DIRENT_HAVE_D_TYPE
      /* We optimize and try to do the lstat call only if needed.  */
      if (direntry->d_type != DT_UNKNOWN)
       lstat_buf.st_mode = DTTOIF (direntry->d_type);
      else
#endif
       if (__builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
         {
           error (0, errno, _("Cannot lstat %s"), file_name);
           continue;
         }

      struct stat64 stat_buf;
      int is_dir;
      int is_link = S_ISLNK (lstat_buf.st_mode);
      if (is_link)
       {
         /* In case of symlink, we check if the symlink refers to
            a directory. */
         if (__builtin_expect (stat64 (real_file_name, &stat_buf), 0))
           {
             if (opt_verbose)
              error (0, errno, _("Cannot stat %s"), file_name);

             /* Remove stale symlinks.  */
             if (strstr (direntry->d_name, ".so."))
              unlink (real_file_name);
             continue;
           }
         is_dir = S_ISDIR (stat_buf.st_mode);

         /* lstat_buf is later stored, update contents.  */
         lstat_buf.st_dev = stat_buf.st_dev;
         lstat_buf.st_ino = stat_buf.st_ino;
         lstat_buf.st_size = stat_buf.st_size;
         lstat_buf.st_ctime = stat_buf.st_ctime;
       }
      else
       is_dir = S_ISDIR (lstat_buf.st_mode);

      if (is_dir && is_hwcap_platform (direntry->d_name))
       {
         /* Handle subdirectory later.  */
         struct dir_entry *new_entry;

         new_entry = xmalloc (sizeof (struct dir_entry));
         new_entry->path = xstrdup (file_name);
         new_entry->flag = entry->flag;
         new_entry->next = NULL;
#ifdef _DIRENT_HAVE_D_TYPE
         /* We have filled in lstat only #ifndef
            _DIRENT_HAVE_D_TYPE.  Fill it in if needed.  */
         if (!is_link
             && direntry->d_type != DT_UNKNOWN
             && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
           {
             error (0, errno, _("Cannot lstat %s"), file_name);
             free (new_entry->path);
             free (new_entry);
             continue;
           }
#endif
         new_entry->ino = lstat_buf.st_ino;
         new_entry->dev = lstat_buf.st_dev;
         add_single_dir (new_entry, 0);
         continue;
       }
      else if (!S_ISREG (lstat_buf.st_mode) && !is_link)
       continue;

      char *real_name;
      if (opt_chroot && is_link)
       {
         real_name = chroot_canon (opt_chroot, file_name);
         if (real_name == NULL)
           {
             if (strstr (file_name, ".so") == NULL)
              error (0, 0, _("Input file %s not found.\n"), file_name);
             continue;
           }
       }
      else
       real_name = real_file_name;

#ifdef _DIRENT_HAVE_D_TYPE
      /* Call lstat64 if not done yet.  */
      if (!is_link
         && direntry->d_type != DT_UNKNOWN
         && __builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
       {
         error (0, errno, _("Cannot lstat %s"), file_name);
         continue;
       }
#endif

      /* First search whether the auxiliary cache contains this
        library already and it's not changed.  */
      char *soname;
      unsigned int osversion;
      if (!search_aux_cache (&lstat_buf, &flag, &osversion, &soname))
       {
         if (process_file (real_name, file_name, direntry->d_name, &flag,
                         &osversion, &soname, is_link, &lstat_buf))
           {
             if (real_name != real_file_name)
              free (real_name);
             continue;
           }
         else if (opt_build_cache)
           add_to_aux_cache (&lstat_buf, flag, osversion, soname);
       }

      if (soname == NULL)
       soname = implicit_soname (direntry->d_name, flag);

      /* A link may just point to itself.  */
      if (is_link)
       {
         /* If the path the link points to isn't its soname and it is not
            .so symlink for ld(1) only, we treat it as a normal file.  */
         const char *real_base_name = basename (real_file_name);

         if (strcmp (real_base_name, soname) != 0)
           {
             len = strlen (real_base_name);
             if (len < strlen (".so")
                || strcmp (real_base_name + len - strlen (".so"), ".so") != 0
                || strncmp (real_base_name, soname, len) != 0)
              is_link = 0;
           }
       }

      if (real_name != real_file_name)
       free (real_name);

      if (is_link)
       {
         free (soname);
         soname = xstrdup (direntry->d_name);
       }

      if (flag == FLAG_ELF
         && (entry->flag == FLAG_ELF_LIBC5
             || entry->flag == FLAG_ELF_LIBC6))
       flag = entry->flag;

      /* Some sanity checks to print warnings.  */
      if (opt_verbose)
       {
         if (flag == FLAG_ELF_LIBC5 && entry->flag != FLAG_ELF_LIBC5
             && entry->flag != FLAG_ANY)
           error (0, 0, _("libc5 library %s in wrong directory"), file_name);
         if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
             && entry->flag != FLAG_ANY)
           error (0, 0, _("libc6 library %s in wrong directory"), file_name);
         if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
             && entry->flag != FLAG_ANY)
           error (0, 0, _("libc4 library %s in wrong directory"), file_name);
       }

      /* Add library to list.  */
      struct dlib_entry *dlib_ptr;
      for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
       {
         /* Is soname already in list?  */
         if (strcmp (dlib_ptr->soname, soname) == 0)
           {
             /* Prefer a file to a link, otherwise check which one
               is newer.  */
             if ((!is_link && dlib_ptr->is_link)
                || (is_link == dlib_ptr->is_link
                    && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
              {
                /* It's newer - add it.  */
                /* Flag should be the same - sanity check.  */
                if (dlib_ptr->flag != flag)
                  {
                    if (dlib_ptr->flag == FLAG_ELF
                       && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
                     dlib_ptr->flag = flag;
                    else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
                            || dlib_ptr->flag == FLAG_ELF_LIBC6)
                            && flag == FLAG_ELF)
                     dlib_ptr->flag = flag;
                    else
                     error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
                            dlib_ptr->name, direntry->d_name,
                            entry->path);
                  }
                free (dlib_ptr->name);
                dlib_ptr->name = xstrdup (direntry->d_name);
                dlib_ptr->is_link = is_link;
                dlib_ptr->osversion = osversion;
              }
             /* Don't add this library, abort loop.  */
             /* Also free soname, since it's dynamically allocated.  */
             free (soname);
             break;
           }
       }
      /* Add the library if it's not already in.  */
      if (dlib_ptr == NULL)
       {
         dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
         dlib_ptr->name = xstrdup (direntry->d_name);
         dlib_ptr->soname = soname;
         dlib_ptr->flag = flag;
         dlib_ptr->is_link = is_link;
         dlib_ptr->osversion = osversion;
         /* Add at head of list.  */
         dlib_ptr->next = dlibs;
         dlibs = dlib_ptr;
       }
    }

  closedir (dir);

  /* Now dlibs contains a list of all libs - add those to the cache
     and created all symbolic links.  */
  struct dlib_entry *dlib_ptr;
  for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
    {
      /* Don't create links to links.  */
      if (dlib_ptr->is_link == 0)
       create_links (dir_name, entry->path, dlib_ptr->name,
                    dlib_ptr->soname);
      if (opt_build_cache)
       add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag,
                    dlib_ptr->osversion, hwcap);
    }

  /* Free all resources.  */
  while (dlibs)
    {
      dlib_ptr = dlibs;
      free (dlib_ptr->soname);
      free (dlib_ptr->name);
      dlibs = dlibs->next;
      free (dlib_ptr);
    }

  if (opt_chroot && dir_name)
    free (dir_name);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void search_dirs ( void  ) [static]

Definition at line 984 of file ldconfig.c.

{
  struct dir_entry *entry;

  for (entry = dir_entries; entry != NULL; entry = entry->next)
    search_dir (entry);

  /* Free all allocated memory.  */
  while (dir_entries)
    {
      entry = dir_entries;
      dir_entries = dir_entries->next;
      free (entry->path);
      free (entry);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_hwcap ( void  ) [static]

Definition at line 1192 of file ldconfig.c.

{
  char *mask = getenv ("LD_HWCAP_MASK");

  if (mask)
    hwcap_mask = strtoul (mask, NULL, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct argp [static]
Initial value:
{
  options, parse_opt, NULL, doc, NULL, NULL, NULL
}

Definition at line 162 of file ldconfig.c.

struct argp_option[] [static]
Initial value:
{
  { "print-cache", 'p', NULL, 0, N_("Print cache"), 0},
  { "verbose", 'v', NULL, 0, N_("Generate verbose messages"), 0},
  { NULL, 'N', NULL, 0, N_("Don't build cache"), 0},
  { NULL, 'X', NULL, 0, N_("Don't generate links"), 0},
  { NULL, 'r', N_("ROOT"), 0, N_("Change to and use ROOT as root directory"), 0},
  { NULL, 'C', N_("CACHE"), 0, N_("Use CACHE as cache file"), 0},
  { NULL, 'f', N_("CONF"), 0, N_("Use CONF as configuration file"), 0},
  { NULL, 'n', NULL, 0, N_("Only process directories specified on the command line.  Don't build cache."), 0},
  { NULL, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
  { "format", 'c', N_("FORMAT"), 0, N_("Format to use: new, old or compat (default)"), 0},
  { "ignore-aux-cache", 'i', NULL, 0, N_("Ignore auxiliary cache file"), 0},
  { NULL, 0, NULL, 0, NULL, 0 }
}

Definition at line 136 of file ldconfig.c.

Definition at line 132 of file ldconfig.c.

char* cache_file [static]

Definition at line 119 of file ldconfig.c.

const char* config_file [static]

Definition at line 122 of file ldconfig.c.

struct dir_entry* dir_entries [static]

Definition at line 87 of file ldconfig.c.

const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.") [static]

Definition at line 156 of file ldconfig.c.

const char* hwcap_extra[64-_DL_FIRST_EXTRA] [static]

Definition at line 128 of file ldconfig.c.

unsigned long int hwcap_mask = HWCAP_IMPORTANT [static]

Definition at line 125 of file ldconfig.c.

struct { ... } lib_types[] [static]
int opt_build_cache = 1 [static]

Definition at line 101 of file ldconfig.c.

char* opt_chroot [static]

Definition at line 110 of file ldconfig.c.

Definition at line 98 of file ldconfig.c.

Definition at line 116 of file ldconfig.c.

int opt_link = 1 [static]

Definition at line 104 of file ldconfig.c.

int opt_manual_link [static]

Definition at line 113 of file ldconfig.c.

int opt_only_cline [static]

Definition at line 107 of file ldconfig.c.

int opt_print_cache [static]

Definition at line 91 of file ldconfig.c.

Definition at line 94 of file ldconfig.c.