-/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; version 2 of the License, or
+ (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
+ This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
+#define PROCINFO_CLASS static
#include <alloca.h>
#include <argp.h>
#include <dirent.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 <stdint.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 <ldconfig.h>
+#include <dl-cache.h>
-#include "dl-procinfo.h"
+#include <dl-procinfo.h>
+
+#ifdef _DL_FIRST_PLATFORM
+# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
+#else
+# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
+#endif
#ifndef LD_SO_CONF
# define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
/* Manually link given shared libraries. */
static int opt_manual_link;
+/* Should we ignore an old auxiliary cache file? */
+static int opt_ignore_aux_cache;
+
/* Cache file to use. */
static char *cache_file;
/* Mask to use for important hardware capabilities. */
static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
+/* Configuration-defined capabilities defined in kernel vDSOs. */
+static const char *hwcap_extra[64 - _DL_FIRST_EXTRA];
+
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
void (*argp_program_version_hook) (FILE *, struct argp_state *)
= print_version;
+/* Function to print some extra text in the help message. */
+static char *more_help (int key, const char *text, void *input);
+
/* Definitions of arguments for argp functions. */
static const struct argp_option options[] =
{
{ "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', "ROOT", 0, N_("Change to and use ROOT as root directory"), 0},
- { NULL, 'C', "CACHE", 0, N_("Use CACHE as cache file"), 0},
- { NULL, 'f', "CONF", 0, N_("Use CONF as configuration file"), 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', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 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 }
};
+#define PROCINFO_CLASS static
+#include <dl-procinfo.c>
+
/* Short description of program. */
static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
/* Data structure to communicate with argp functions. */
static struct argp argp =
{
- options, parse_opt, NULL, doc, NULL, NULL, NULL
+ options, parse_opt, NULL, doc, NULL, more_help, NULL
};
/* Check if string corresponds to an important hardware capability or
{
int hwcap_idx = _dl_string_hwcap (name);
+ /* Is this a normal hwcap for the machine like "fpu?" */
if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask))
return 1;
+ /* Is this a platform pseudo-hwcap like "i686?" */
hwcap_idx = _dl_string_platform (name);
if (hwcap_idx != -1)
return 1;
+ /* Is this one of the extra pseudo-hwcaps that we map beyond
+ _DL_FIRST_EXTRA like "tls", or "nosegneg?" */
+ 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;
}
{
h = _dl_string_platform (ptr + 1);
if (h == (uint64_t) -1)
- break;
+ {
+ 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;
{
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;
return 0;
}
+/* Print bug-reporting information in the help message. */
+static char *
+more_help (int key, const char *text, void *input)
+{
+ char *tp = NULL;
+ switch (key)
+ {
+ case ARGP_KEY_HELP_EXTRA:
+ /* We print some extra information. */
+ if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+ return NULL;
+ return tp;
+ default:
+ break;
+ }
+ return (char *) text;
+}
+
/* Print the version information. */
static void
print_version (FILE *stream, struct argp_state *state)
{
- fprintf (stream, "ldconfig (GNU %s) %s\n", PACKAGE, VERSION);
+ fprintf (stream, "ldconfig %s%s\n", PKGVERSION, 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\
-"), "2001");
+"), "2013");
fprintf (stream, gettext ("Written by %s.\n"),
"Andreas Jaeger");
}
static void
add_dir (const char *line)
{
- char *equal_sign;
- struct dir_entry *entry;
unsigned int i;
- struct stat64 stat_buf;
-
- entry = xmalloc (sizeof (struct dir_entry));
+ struct dir_entry *entry = xmalloc (sizeof (struct dir_entry));
entry->next = NULL;
/* Search for an '=' sign. */
entry->path = xstrdup (line);
- equal_sign = strchr (entry->path, '=');
+ char *equal_sign = strchr (entry->path, '=');
if (equal_sign)
{
*equal_sign = '\0';
entry->flag = FLAG_ANY;
}
- /* Canonify path: for now only remove trailing slashes. */
- i = strlen (entry->path) - 1;
- while (entry->path[i] == '/' && i > 0)
- {
- entry->path[i] = '\0';
- --i;
- }
+ /* Canonify path: for now only remove leading and trailing
+ whitespace and the trailing slashes. */
+ i = strlen (entry->path);
+
+ while (i > 0 && isspace (entry->path[i - 1]))
+ entry->path[--i] = '\0';
+
+ while (i > 0 && entry->path[i - 1] == '/')
+ entry->path[--i] = '\0';
+
+ if (i == 0)
+ return;
+
+ char *path = entry->path;
+ if (opt_chroot)
+ path = chroot_canon (opt_chroot, path);
- if (stat64 (entry->path, &stat_buf))
+ 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);
- return;
}
+ else
+ {
+ entry->ino = stat_buf.st_ino;
+ entry->dev = stat_buf.st_dev;
- entry->ino = stat_buf.st_ino;
- entry->dev = stat_buf.st_dev;
+ add_single_dir (entry, 1);
+ }
- add_single_dir (entry, 1);
+ if (opt_chroot)
+ free (path);
}
if (libname)
{
/* Successfully split names. Check if path is just "/" to avoid
- an empty path. */
+ an empty path. */
if (libname == path)
{
libname = library + 1;
/* Do some sanity checks first. */
if (lstat64 (real_library, &stat_buf))
{
- error (0, errno, _("Can't lstat %s"), library);
+ error (0, errno, _("Cannot lstat %s"), library);
free (path);
return;
}
free (path);
return;
}
+
if (process_file (real_library, library, libname, &flag, &osversion,
- &soname, 0))
+ &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);
static void
search_dir (const struct dir_entry *entry)
{
- DIR *dir;
- struct dirent *direntry;
- char *file_name, *dir_name, *real_file_name, *real_name;
- int file_name_len, real_file_name_len, len;
- char *soname;
- struct dlib_entry *dlibs;
- struct dlib_entry *dlib_ptr;
- struct stat64 lstat_buf, stat_buf;
- int is_link, is_dir;
uint64_t hwcap = path_hwcap (entry->path);
- unsigned int osversion;
-
- file_name_len = PATH_MAX;
- file_name = alloca (file_name_len);
-
- dlibs = NULL;
-
if (opt_verbose)
{
if (hwcap != 0)
- printf ("%s: (hwcap: 0x%" PRIx64 ")\n", entry->path, hwcap);
+ 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 = file_name;
}
+ DIR *dir;
if (dir_name == NULL || (dir = opendir (dir_name)) == NULL)
{
if (opt_verbose)
return;
}
- while ((direntry = readdir (dir)) != NULL)
+ struct dirent64 *direntry;
+ struct dlib_entry *dlibs = NULL;
+ while ((direntry = readdir64 (dir)) != NULL)
{
int flag;
#ifdef _DIRENT_HAVE_D_TYPE
if (((strncmp (direntry->d_name, "lib", 3) != 0
&& strncmp (direntry->d_name, "ld-", 3) != 0)
|| strstr (direntry->d_name, ".so") == NULL)
- && !is_hwcap_platform (direntry->d_name))
+ && (
+#ifdef _DIRENT_HAVE_D_TYPE
+ direntry->d_type == DT_REG ||
+#endif
+ !is_hwcap_platform (direntry->d_name)))
continue;
- len = strlen (entry->path) + strlen (direntry->d_name);
+
+ 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 + 1;
+ 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);
+ len = strlen (dir_name) + strlen (direntry->d_name) + 2;
if (len > real_file_name_len)
{
- real_file_name_len = len + 1;
+ 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 (lstat64 (real_file_name, &lstat_buf))
+ if (__builtin_expect (lstat64 (real_file_name, &lstat_buf), 0))
{
- error (0, errno, _("Can't lstat %s"), file_name);
+ error (0, errno, _("Cannot lstat %s"), file_name);
continue;
}
- is_link = S_ISLNK (lstat_buf.st_mode);
+ 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 (stat64 (real_file_name, &stat_buf))
+ char *target_name = real_file_name;
+ if (opt_chroot)
+ {
+ target_name = chroot_canon (opt_chroot, file_name);
+ if (target_name == NULL)
+ {
+ if (strstr (file_name, ".so") == NULL)
+ error (0, 0, _("Input file %s not found.\n"), file_name);
+ continue;
+ }
+ }
+ if (__builtin_expect (stat64 (target_name, &stat_buf), 0))
{
if (opt_verbose)
- error (0, errno, _("Can't stat %s"), file_name);
+ 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);
new_entry->path = xstrdup (file_name);
new_entry->flag = entry->flag;
new_entry->next = NULL;
- if (is_link)
- {
- new_entry->ino = stat_buf.st_ino;
- new_entry->dev = stat_buf.st_dev;
- }
- else
+#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))
{
- new_entry->ino = lstat_buf.st_ino;
- new_entry->dev = lstat_buf.st_dev;
+ 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);
else
real_name = real_file_name;
- if (process_file (real_name, file_name, direntry->d_name, &flag,
- &osversion, &soname, is_link))
+#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))
{
- if (real_name != real_file_name)
- free (real_name);
+ 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);
- /* Links will just point to itself. */
if (is_link)
{
free (soname);
&& (entry->flag == FLAG_ELF_LIBC5
|| entry->flag == FLAG_ELF_LIBC6))
flag = entry->flag;
+
/* Some sanity checks to print warnings. */
if (opt_verbose)
{
}
/* 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? */
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);
+ dlib_ptr->name, direntry->d_name,
+ entry->path);
}
free (dlib_ptr->name);
- dlib_ptr->osversion = osversion;
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. */
{
dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
dlib_ptr->name = xstrdup (direntry->d_name);
- dlib_ptr->flag = flag;
- dlib_ptr->osversion = osversion;
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;
/* 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. */
}
+static void parse_conf_include (const char *config_file, unsigned int lineno,
+ bool do_chroot, const char *pattern);
+
/* Parse configuration file. */
static void
-parse_conf (const char *filename)
+parse_conf (const char *filename, bool do_chroot)
{
FILE *file = NULL;
char *line = NULL;
const char *canon;
size_t len = 0;
+ unsigned int lineno;
- if (opt_chroot)
+ if (do_chroot && opt_chroot)
{
canon = chroot_canon (opt_chroot, filename);
if (canon)
if (file == NULL)
{
- error (0, errno, _("Can't open configuration file %s"), canon);
+ error (0, errno, _("\
+Warning: ignoring configuration file that cannot be opened: %s"),
+ canon);
if (canon != filename)
free ((char *) canon);
return;
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';
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 (line[0] == '\0')
+ if (cp[0] == '\0')
continue;
- add_dir (line);
- } while (!feof (file));
+ 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);
}
+/* Handle one word in an `include' line, a glob pattern of additional
+ config files to read. */
+static void
+parse_conf_include (const char *config_file, unsigned int lineno,
+ bool do_chroot, const char *pattern)
+{
+ 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 (©, "%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);
+ if (canon == NULL)
+ return;
+ result = glob64 (canon, 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);
+}
+
/* Honour LD_HWCAP_MASK. */
static void
set_hwcap (void)
int
main (int argc, char **argv)
{
- int remaining;
+ /* 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 libraries if opt_manual_link
+ /* 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)
- add_dir (argv[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]);
}
+ /* The last entry in hwcap_extra is reserved for the "tls" pseudo-hwcap which
+ indicates support for TLS. This pseudo-hwcap is only used by old versions
+ under which TLS support was optional. The entry is no longer needed, but
+ must remain for compatibility. */
+ 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 = strchr (opt_chroot, '\0');
+ char *endp = rawmemchr (opt_chroot, '\0');
while (endp > opt_chroot && endp[-1] == '/')
--endp;
*endp = '\0';
if (opt_chroot)
{
/* Canonicalize the directory name of cache_file, not cache_file,
- because we'll rename a temporary cache file to it. */
+ 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 : "/");
- }
+ error (EXIT_FAILURE, errno,
+ _("Can't open cache file directory %s\n"),
+ p ? cache_file : "/");
if (p)
++p;
if (!opt_only_cline)
{
+ parse_conf (config_file, true);
+
/* Always add the standard search paths. */
- add_dir (SLIBDIR);
+ add_system_dir (SLIBDIR);
if (strcmp (SLIBDIR, LIBDIR))
- add_dir (LIBDIR);
-
- parse_conf (config_file);
+ add_system_dir (LIBDIR);
}
+ const char *aux_cache_file = _PATH_LDCONFIG_AUX_CACHE;
+ if (opt_chroot)
+ aux_cache_file = chroot_canon (opt_chroot, aux_cache_file);
+
+ if (! opt_ignore_aux_cache && aux_cache_file)
+ load_aux_cache (aux_cache_file);
+ else
+ init_aux_cache ();
+
search_dirs ();
if (opt_build_cache)
- save_cache (cache_file);
+ {
+ save_cache (cache_file);
+ if (aux_cache_file)
+ save_aux_cache (aux_cache_file);
+ }
return 0;
}