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