mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
Update.
1999-11-30 Andreas Jaeger <aj@suse.de> Add ldconfig: * elf/Makefile (extra-objs): Added ldconfig-modules. (ldconfig-modules): New. Added vpath for xstrdup and xmalloc. Check for use-ldconfig instead of has-ldconfig. ($(objpfx)ldconfig): New rule with dependencies. (distribute): Add new files. * sysdeps/unix/sysv/linux/sparc/readelflib.c: New file, developed together with Jakub Jelinek <jakub@redhat.com>. * sysdeps/generic/readelflib.c: Likewise. * elf/cache.c: New file. * elf/ldconfig.c: New file. * elf/ldconfig.h: New file. * elf/readlib.c: New file. * Makefile (install): Remove flag -d in ldconfig call. * configure.in: Rename has_ldconfig to use_ldconfig, set it to no by default. * config.make.in (has-ldconfig): Renamed to use-ldconfig, changed comment.
This commit is contained in:
parent
589328764d
commit
591e1ffbf8
27
ChangeLog
27
ChangeLog
@ -1,3 +1,30 @@
|
||||
1999-11-30 Andreas Jaeger <aj@suse.de>
|
||||
|
||||
Add ldconfig:
|
||||
* elf/Makefile (extra-objs): Added ldconfig-modules.
|
||||
(ldconfig-modules): New.
|
||||
Added vpath for xstrdup and xmalloc.
|
||||
Check for use-ldconfig instead of has-ldconfig.
|
||||
($(objpfx)ldconfig): New rule with dependencies.
|
||||
(distribute): Add new files.
|
||||
|
||||
* sysdeps/unix/sysv/linux/sparc/readelflib.c: New file,
|
||||
developed together with Jakub Jelinek <jakub@redhat.com>.
|
||||
* sysdeps/generic/readelflib.c: Likewise.
|
||||
|
||||
* elf/cache.c: New file.
|
||||
* elf/ldconfig.c: New file.
|
||||
* elf/ldconfig.h: New file.
|
||||
* elf/readlib.c: New file.
|
||||
|
||||
* Makefile (install): Remove flag -d in ldconfig call.
|
||||
|
||||
* configure.in: Rename has_ldconfig to use_ldconfig, set it to no
|
||||
by default.
|
||||
|
||||
* config.make.in (has-ldconfig): Renamed to use-ldconfig, changed
|
||||
comment.
|
||||
|
||||
1999-12-03 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* sysdeps/generic/bits/stropts.h: Update with LiS types and
|
||||
|
2
NEWS
2
NEWS
@ -20,6 +20,8 @@ Version 2.2
|
||||
* Functions feenableexcept and fedisableexcept to control the
|
||||
behaviour of individual exceptions have been added by Andreas Jaeger.
|
||||
|
||||
* ldconfig program added by Andreas Jaeger and Jakub Jelinek.
|
||||
|
||||
|
||||
Version 2.1.2
|
||||
|
||||
|
@ -15,9 +15,8 @@ sysconfdir = @libc_cv_sysconfdir@
|
||||
libexecdir = @libexecdir@
|
||||
rootsbindir = @libc_cv_rootsbindir@
|
||||
|
||||
# If ldconfig exists. This will go away as soon as `ldconfig' is available
|
||||
# in GNU libc.
|
||||
has-ldconfig = @has_ldconfig@
|
||||
# Should we use and build ldconfig?
|
||||
use-ldconfig = @use_ldconfig@
|
||||
|
||||
# Maybe the `ldd' script must be rewritten.
|
||||
ldd-rewrite-script = @ldd_rewrite_script@
|
||||
|
@ -1168,6 +1168,7 @@ libc_link_dests=
|
||||
libc_link_sources=
|
||||
|
||||
# They also can set these variables.
|
||||
use_ldconfig=no
|
||||
ldd_rewrite_script=no
|
||||
|
||||
# Iterate over all the sysdep directories we will use, running their
|
||||
@ -1282,7 +1283,7 @@ AC_SUBST(libc_cv_slibdir)
|
||||
AC_SUBST(libc_cv_sysconfdir)
|
||||
AC_SUBST(libc_cv_rootsbindir)
|
||||
|
||||
AC_SUBST(has_ldconfig)
|
||||
AC_SUBST(use_ldconfig)
|
||||
AC_SUBST(ldd_rewrite_script)
|
||||
|
||||
AC_SUBST(gnu_ld) AC_SUBST(gnu_as) AC_SUBST(elf)
|
||||
|
14
elf/Makefile
14
elf/Makefile
@ -41,7 +41,8 @@ distribute := $(rtld-routines:=.c) dynamic-link.h do-rel.h dl-machine.h \
|
||||
dl-librecon.h interp.c sln.c dl-dst.h hp-timing.h \
|
||||
do-lookup.h sprof.c gen-trusted-dirs.awk \
|
||||
testobj1.c testobj2.c testobj3.c testobj4.c testobj5.c \
|
||||
testobj6.c testobj1_1.c failobj.c
|
||||
testobj6.c testobj1_1.c failobj.c \
|
||||
ldconfig.h ldconfig.c cache.c readlib.c readelflib.c
|
||||
|
||||
include ../Makeconfig
|
||||
|
||||
@ -64,10 +65,17 @@ install-bin += sprof
|
||||
others-static = sln
|
||||
install-rootsbin = sln
|
||||
|
||||
ifeq (yes,$(has-ldconfig))
|
||||
ifeq (yes,$(use-ldconfig))
|
||||
others-static += ldconfig
|
||||
others += ldconfig
|
||||
install-rootsbin += ldconfig
|
||||
|
||||
ldconfig-modules := cache readlib xmalloc xstrdup
|
||||
extra-objs += $(ldconfig-modules:=.o)
|
||||
|
||||
# To find xmalloc.c and xstrdup.c
|
||||
vpath %.c ../locale/programs
|
||||
|
||||
endif
|
||||
|
||||
ifeq (yes,$(build-shared))
|
||||
@ -191,6 +199,8 @@ $(objpfx)ldd: ldd.bash.in $(common-objpfx)soversions.mk \
|
||||
|
||||
$(objpfx)sprof: $(libdl)
|
||||
|
||||
$(objpfx)ldconfig: $(ldconfig-modules:%=$(objpfx)%.o)
|
||||
|
||||
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
||||
generated += $(addsuffix .so,$(modules-names))
|
||||
|
||||
|
363
elf/cache.c
Normal file
363
elf/cache.c
Normal file
@ -0,0 +1,363 @@
|
||||
/* Copyright (C) 1999 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 Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <error.h>
|
||||
#include <dirent.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.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 "ldconfig.h"
|
||||
|
||||
#define CACHEMAGIC "ld.so-1.7.0"
|
||||
|
||||
struct cache_entry
|
||||
{
|
||||
char *lib;
|
||||
char *path;
|
||||
int flags;
|
||||
struct cache_entry *next;
|
||||
};
|
||||
|
||||
struct file_entry
|
||||
{
|
||||
int flags; /* This is 1 for an ELF library. */
|
||||
unsigned int key, value; /* String table indices. */
|
||||
};
|
||||
|
||||
|
||||
struct cache_file
|
||||
{
|
||||
char magic[sizeof CACHEMAGIC - 1];
|
||||
unsigned int nlibs;
|
||||
struct file_entry libs[0];
|
||||
};
|
||||
|
||||
|
||||
/* List of all cache entries. */
|
||||
static struct cache_entry *entries;
|
||||
|
||||
static const char *flag_descr[] =
|
||||
{ "libc4", "ELF", "libc5", "libc6"};
|
||||
|
||||
|
||||
/* Print a single entry. */
|
||||
static void
|
||||
print_entry (const char *lib, int flag, const char *key)
|
||||
{
|
||||
printf ("\t%s (", lib);
|
||||
switch (flag)
|
||||
{
|
||||
case FLAG_LIBC4:
|
||||
case FLAG_ELF:
|
||||
case FLAG_ELF_LIBC5:
|
||||
case FLAG_ELF_LIBC6:
|
||||
fputs (flag_descr [flag & FLAG_TYPE_MASK], stdout);
|
||||
break;
|
||||
default:
|
||||
fputs ("unknown", stdout);
|
||||
break;
|
||||
}
|
||||
switch (flag & FLAG_REQUIRED_MASK)
|
||||
{
|
||||
#ifdef __sparc__
|
||||
case FLAG_SPARC_LIB64:
|
||||
fputs (",64bit", stdout);
|
||||
#endif
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
fprintf (stdout, ",%d", flag & FLAG_REQUIRED_MASK);
|
||||
break;
|
||||
}
|
||||
printf (") => %s\n", key);
|
||||
}
|
||||
|
||||
|
||||
/* Print the whole cache file. */
|
||||
void
|
||||
print_cache (const char *cache_name)
|
||||
{
|
||||
size_t cache_size;
|
||||
struct stat st;
|
||||
int fd;
|
||||
unsigned int i;
|
||||
struct cache_file *cache;
|
||||
const char *cache_data;
|
||||
|
||||
fd = open (cache_name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
error (EXIT_FAILURE, errno, _("Can't open cache file %s\n"), cache_name);
|
||||
|
||||
if (fstat (fd, &st) < 0
|
||||
/* No need to map the file if it is empty. */
|
||||
|| st.st_size == 0)
|
||||
{
|
||||
close (fd);
|
||||
return;
|
||||
}
|
||||
|
||||
cache = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (cache == MAP_FAILED)
|
||||
error (EXIT_FAILURE, errno, _("mmap of cache file failed.\n"));
|
||||
cache_size = st.st_size;
|
||||
|
||||
if (cache_size < sizeof (struct cache_file)
|
||||
|| memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
|
||||
return;
|
||||
/* This is where the strings start. */
|
||||
cache_data = (const char *) &cache->libs[cache->nlibs];
|
||||
|
||||
printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
|
||||
|
||||
/* Print everything. */
|
||||
for (i = 0; i < cache->nlibs; i++)
|
||||
print_entry (cache_data + cache->libs[i].key,
|
||||
cache->libs[i].flags,
|
||||
cache_data + cache->libs[i].value);
|
||||
|
||||
/* Cleanup. */
|
||||
munmap (cache, cache_size);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/* Initialize cache data structures. */
|
||||
void
|
||||
init_cache (void)
|
||||
{
|
||||
entries = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Helper function which must match the one in the dynamic linker, so that
|
||||
we rely on the same sort order. */
|
||||
int
|
||||
cache_libcmp (const char *p1, const char *p2)
|
||||
{
|
||||
while (*p1 != '\0')
|
||||
{
|
||||
if (*p1 >= '0' && *p1 <= '9')
|
||||
{
|
||||
if (*p2 >= '0' && *p2 <= '9')
|
||||
{
|
||||
/* Must compare this numerically. */
|
||||
int val1;
|
||||
int val2;
|
||||
|
||||
val1 = *p1++ - '0';
|
||||
val2 = *p2++ - '0';
|
||||
while (*p1 >= '0' && *p1 <= '9')
|
||||
val1 = val1 * 10 + *p1++ - '0';
|
||||
while (*p2 >= '0' && *p2 <= '9')
|
||||
val2 = val2 * 10 + *p2++ - '0';
|
||||
if (val1 != val2)
|
||||
return val1 - val2;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else if (*p2 >= '0' && *p2 <= '9')
|
||||
return -1;
|
||||
else if (*p1 != *p2)
|
||||
return *p1 - *p2;
|
||||
else
|
||||
{
|
||||
++p1;
|
||||
++p2;
|
||||
}
|
||||
}
|
||||
return *p1 - *p2;
|
||||
}
|
||||
|
||||
static
|
||||
int compare (const struct cache_entry *e1, const struct cache_entry *e2)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* We need to swap entries here to get the correct sort order. */
|
||||
res = cache_libcmp (e2->lib, e1->lib);
|
||||
if (res == 0)
|
||||
{
|
||||
if (e1->flags < e2->flags)
|
||||
return 1;
|
||||
else if (e1->flags > e2->flags)
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Save the contents of the cache. */
|
||||
void
|
||||
save_cache (const char *cache_name)
|
||||
{
|
||||
struct cache_entry *entry;
|
||||
int i, fd;
|
||||
size_t total_strlen, len;
|
||||
char *strings, *str, *temp_name;
|
||||
struct cache_file *file_entries;
|
||||
size_t file_entries_size;
|
||||
unsigned int str_offset;
|
||||
/* Number of cache entries. */
|
||||
int cache_entry_count = 0;
|
||||
|
||||
/* The cache entries are sorted already, save them in this order. */
|
||||
|
||||
/* Count the length of all strings. */
|
||||
total_strlen = 0;
|
||||
for (entry = entries; entry != NULL; entry = entry->next)
|
||||
{
|
||||
/* Account the final NULs. */
|
||||
total_strlen += strlen (entry->lib) + strlen (entry->path) + 2;
|
||||
++cache_entry_count;
|
||||
}
|
||||
|
||||
/* Create the on disk cache structure. */
|
||||
/* First an array for all strings. */
|
||||
strings = (char *)xmalloc (total_strlen + 1);
|
||||
|
||||
/* And the list of all entries. */
|
||||
file_entries_size = sizeof (struct cache_file)
|
||||
+ cache_entry_count * sizeof (struct file_entry);
|
||||
file_entries = (struct cache_file *) xmalloc (file_entries_size);
|
||||
|
||||
/* Fill in the header. */
|
||||
memset (file_entries, 0, sizeof (struct cache_file));
|
||||
memcpy (file_entries->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1);
|
||||
|
||||
file_entries->nlibs = cache_entry_count;
|
||||
|
||||
str_offset = 0;
|
||||
str = strings;
|
||||
for (i = 0, entry = entries; entry != NULL; entry = entry->next, ++i)
|
||||
{
|
||||
file_entries->libs[i].flags = entry->flags;
|
||||
/* First the library. */
|
||||
/* XXX: Actually we can optimize here and remove duplicates. */
|
||||
file_entries->libs[i].key = str_offset;
|
||||
len = strlen (entry->lib);
|
||||
str = stpcpy (str, entry->lib);
|
||||
/* Account the final NUL. */
|
||||
++str;
|
||||
str_offset += len + 1;
|
||||
/* Then the path. */
|
||||
file_entries->libs[i].value = str_offset;
|
||||
len = strlen (entry->path);
|
||||
str = stpcpy (str, entry->path);
|
||||
/* Account the final NUL. */
|
||||
++str;
|
||||
str_offset += len + 1;
|
||||
}
|
||||
assert (str_offset == total_strlen);
|
||||
|
||||
/* Write out the cache. */
|
||||
|
||||
/* Write cache first to a temporary file and rename it later. */
|
||||
temp_name = xmalloc (strlen (cache_name) + 2);
|
||||
sprintf (temp_name, "%s~", cache_name);
|
||||
/* First remove an old copy if it exists. */
|
||||
if (unlink (temp_name) && errno != ENOENT)
|
||||
error (EXIT_FAILURE, errno, _("Can't remove old temporary cache file %s"),
|
||||
temp_name);
|
||||
|
||||
/* Create file. */
|
||||
fd = open (temp_name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, 0644);
|
||||
if (fd < 0)
|
||||
error (EXIT_FAILURE, errno, _("Can't create temporary cache file %s"),
|
||||
temp_name);
|
||||
|
||||
/* Write contents. */
|
||||
if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size)
|
||||
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
|
||||
|
||||
if (write (fd, strings, total_strlen) != (ssize_t)total_strlen)
|
||||
error (EXIT_FAILURE, errno, _("Writing of cache data failed."));
|
||||
|
||||
close (fd);
|
||||
|
||||
/* Move temporary to its final location. */
|
||||
if (rename (temp_name, cache_name))
|
||||
error (EXIT_FAILURE, errno, _("Renaming of %s to %s failed"), temp_name,
|
||||
cache_name);
|
||||
|
||||
/* Free all allocated memory. */
|
||||
free (file_entries);
|
||||
free (strings);
|
||||
|
||||
while (entries)
|
||||
{
|
||||
entry = entries;
|
||||
free (entry->path);
|
||||
free (entry->lib);
|
||||
entries = entries->next;
|
||||
free (entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add one library to the cache. */
|
||||
void
|
||||
add_to_cache (const char *path, const char *lib, int flags)
|
||||
{
|
||||
struct cache_entry *new_entry, *ptr, *prev;
|
||||
char *full_path;
|
||||
int len;
|
||||
|
||||
new_entry = (struct cache_entry *) xmalloc (sizeof (struct cache_entry));
|
||||
|
||||
len = strlen (lib) + strlen (path) + 2;
|
||||
|
||||
full_path = (char *) xmalloc (len);
|
||||
snprintf (full_path, len, "%s/%s", path, lib);
|
||||
|
||||
new_entry->lib = xstrdup (lib);
|
||||
new_entry->path = full_path;
|
||||
new_entry->flags = flags;
|
||||
|
||||
/* Keep the list sorted - search for right place to insert. */
|
||||
ptr = entries;
|
||||
prev = entries;
|
||||
while (ptr != NULL)
|
||||
{
|
||||
if (compare (ptr, new_entry) > 0)
|
||||
break;
|
||||
prev = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
/* Is this the first entry? */
|
||||
if (ptr == entries)
|
||||
{
|
||||
new_entry->next = entries;
|
||||
entries = new_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_entry->next = prev->next;
|
||||
prev->next = new_entry;
|
||||
}
|
||||
}
|
647
elf/ldconfig.c
Normal file
647
elf/ldconfig.c
Normal file
@ -0,0 +1,647 @@
|
||||
/* Copyright (C) 1999 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 Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <argp.h>
|
||||
#include <dirent.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.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 "ldconfig.h"
|
||||
|
||||
#ifndef LD_SO_CACHE
|
||||
# define LD_SO_CACHE "/etc/ld.so.cache"
|
||||
#endif
|
||||
|
||||
#ifndef LD_SO_CONF
|
||||
# define LD_SO_CONF "/etc/ld.so.conf"
|
||||
#endif
|
||||
|
||||
/* Get libc version number. */
|
||||
#include <version.h>
|
||||
|
||||
#define PACKAGE _libc_intl_domainname
|
||||
|
||||
struct lib_entry
|
||||
{
|
||||
int flags;
|
||||
char *lib;
|
||||
char *path;
|
||||
};
|
||||
|
||||
static const struct
|
||||
{
|
||||
const char *name;
|
||||
int flag;
|
||||
} lib_types [] =
|
||||
{
|
||||
{"libc4", FLAG_LIBC4},
|
||||
{"libc5", FLAG_ELF_LIBC5},
|
||||
{"libc6", FLAG_ELF_LIBC6},
|
||||
{"glibc2", FLAG_ELF_LIBC6}
|
||||
};
|
||||
|
||||
|
||||
/* List of directories to handle. */
|
||||
struct dir_entry
|
||||
{
|
||||
char *path;
|
||||
int flag;
|
||||
struct dir_entry *next;
|
||||
};
|
||||
|
||||
/* The list is unsorted, contains no duplicates. Entries are added at
|
||||
the end. */
|
||||
static struct dir_entry *dir_entries;
|
||||
|
||||
/* Flags for different options. */
|
||||
/* Print Cache. */
|
||||
static int opt_print_cache = 0;
|
||||
|
||||
/* Be verbose. */
|
||||
int opt_verbose = 0;
|
||||
|
||||
/* Build cache. */
|
||||
static int opt_build_cache = 1;
|
||||
|
||||
/* Generate links. */
|
||||
static int opt_link = 1;
|
||||
|
||||
/* Only process directories specified on the command line. */
|
||||
static int opt_only_cline = 0;
|
||||
|
||||
/* Path to root for chroot. */
|
||||
static char *opt_chroot;
|
||||
|
||||
/* Cache file to use. */
|
||||
static const char *cache_file;
|
||||
|
||||
/* Configuration file. */
|
||||
static const char *config_file;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Definitions of arguments for argp functions. */
|
||||
static const struct argp_option options[] =
|
||||
{
|
||||
{ "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', "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, 'n', NULL, 0, N_("Only process directories specified on the command line. Don't build cache."), 0},
|
||||
{ NULL, 0, NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/* Short description of program. */
|
||||
static const char doc[] = N_("Configure Dynamic Linker Run Time Bindings.");
|
||||
|
||||
/* Prototype for option handler. */
|
||||
static error_t parse_opt (int key, char *arg, struct argp_state *state);
|
||||
|
||||
/* Data structure to communicate with argp functions. */
|
||||
static struct argp argp =
|
||||
{
|
||||
options, parse_opt, NULL, doc, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Handle program arguments. */
|
||||
static error_t
|
||||
parse_opt (int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case 'C':
|
||||
cache_file = arg;
|
||||
break;
|
||||
case 'f':
|
||||
config_file = arg;
|
||||
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;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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, 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\
|
||||
"), "1999");
|
||||
fprintf (stream, gettext ("Written by %s.\n"),
|
||||
"Andreas Jaeger");
|
||||
}
|
||||
|
||||
/* Add one directory to the list of directories to process. */
|
||||
static void
|
||||
add_dir (const char *line)
|
||||
{
|
||||
char *equal_sign;
|
||||
struct dir_entry *entry, *ptr, *prev;
|
||||
unsigned int i;
|
||||
|
||||
entry = xmalloc (sizeof (struct dir_entry));
|
||||
entry->next = NULL;
|
||||
|
||||
/* Search for an '=' sign. */
|
||||
entry->path = xstrdup (line);
|
||||
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 trailing slashes. */
|
||||
i = strlen (entry->path) - 1;
|
||||
while (entry->path[i] == '/' && i > 0)
|
||||
{
|
||||
entry->path [i] = '\0';
|
||||
--i;
|
||||
}
|
||||
|
||||
ptr = dir_entries;
|
||||
prev = ptr;
|
||||
while (ptr != NULL)
|
||||
{
|
||||
/* Check for duplicates. */
|
||||
if (strcmp (ptr->path, entry->path) == 0)
|
||||
{
|
||||
if (opt_verbose)
|
||||
error (0, 0, _("Path `%s' given more than once"), entry->path);
|
||||
/* Use the newer information. */
|
||||
ptr->flag = entry->flag;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Create a symbolic link from soname to libname in directory path. */
|
||||
static void
|
||||
create_links (const char *path, const char *libname, const char *soname)
|
||||
{
|
||||
char full_libname [PATH_MAX], full_soname [PATH_MAX];
|
||||
struct stat 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. */
|
||||
snprintf (full_libname, sizeof full_libname, "%s/%s", path, libname);
|
||||
snprintf (full_soname, sizeof full_soname, "%s/%s", path, soname);
|
||||
|
||||
/* Does soname already exist and point to the right library? */
|
||||
if (stat (full_soname, &stat_so) == 0)
|
||||
{
|
||||
if (stat (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 (lstat (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 (lstat (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 (full_soname))
|
||||
{
|
||||
error (0, 0, _("Can't unlink %s"), full_soname);
|
||||
do_link = 0;
|
||||
}
|
||||
/* Create symbolic link. */
|
||||
if (do_link && symlink (libname, 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);
|
||||
}
|
||||
|
||||
/* Read a whole directory and search for libraries.
|
||||
The purpose is two-fold:
|
||||
- search for libraries which will be added to the cache
|
||||
- create symbolic links to the soname for each library
|
||||
|
||||
This has to be done separatly for each directory.
|
||||
|
||||
To keep track of which libraries to add to the cache and which
|
||||
links to create, we save a list of all libraries.
|
||||
|
||||
The algorithm is basically:
|
||||
for all libraries in the directory do
|
||||
get soname of library
|
||||
if soname is already in list
|
||||
if new library is newer, replace entry
|
||||
otherwise ignore this library
|
||||
otherwise add library to list
|
||||
|
||||
For example, if the two libraries libxy.so.1.1 and libxy.so.1.2
|
||||
exist and both have the same soname, e.g. libxy.so, a symbolic link
|
||||
is created from libxy.so.1.2 (the newer one) to libxy.so.
|
||||
libxy.so.1.2 and libxy.so are added to the cache - but not
|
||||
libxy.so.1.1. */
|
||||
|
||||
/* Information for one library. */
|
||||
struct dlib_entry
|
||||
{
|
||||
char *name;
|
||||
char *soname;
|
||||
int flag;
|
||||
int is_link;
|
||||
struct dlib_entry *next;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
search_dir (const struct dir_entry *entry)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *direntry;
|
||||
char buf [PATH_MAX];
|
||||
char *soname;
|
||||
struct dlib_entry *dlibs;
|
||||
struct dlib_entry *dlib_ptr;
|
||||
int nchars;
|
||||
struct stat stat_buf;
|
||||
int is_link;
|
||||
|
||||
dlibs = NULL;
|
||||
|
||||
if (opt_verbose)
|
||||
printf ("%s:\n", entry->path);
|
||||
|
||||
dir = opendir (entry->path);
|
||||
if (dir == NULL)
|
||||
{
|
||||
if (opt_verbose)
|
||||
error (0, errno, _("Can't open directory %s"), entry->path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while ((direntry = readdir (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)
|
||||
continue;
|
||||
#endif /* _DIRENT_HAVE_D_TYPE */
|
||||
|
||||
/* Does this file look like a shared library? 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)
|
||||
continue;
|
||||
nchars = snprintf (buf, sizeof (buf), "%s/%s", entry->path,
|
||||
direntry->d_name);
|
||||
/* Check for overflow. */
|
||||
if (nchars >= (int) sizeof (buf))
|
||||
{
|
||||
error (0, 0, _("buffer for snprintf too small for %s/%s--file is ignored\n"),
|
||||
entry->path, direntry->d_name);
|
||||
continue;
|
||||
}
|
||||
if (lstat (buf, &stat_buf))
|
||||
{
|
||||
error (0, errno, _("Can't lstat %s"), buf);
|
||||
continue;
|
||||
}
|
||||
else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode))
|
||||
continue;
|
||||
|
||||
is_link = S_ISLNK (stat_buf.st_mode);
|
||||
|
||||
if (process_file (buf, direntry->d_name, &flag, &soname, is_link))
|
||||
continue;
|
||||
|
||||
/* Links will just point to itself. */
|
||||
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"), buf);
|
||||
if (flag == FLAG_ELF_LIBC6 && entry->flag != FLAG_ELF_LIBC6
|
||||
&& entry->flag != FLAG_ANY)
|
||||
error (0, 0, _("libc6 library %s in wrong directory"), buf);
|
||||
if (flag == FLAG_LIBC4 && entry->flag != FLAG_LIBC4
|
||||
&& entry->flag != FLAG_ANY)
|
||||
error (0, 0, _("libc4 library %s in wrong directory"), buf);
|
||||
}
|
||||
|
||||
/* Add library to list. */
|
||||
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
|
||||
&& 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;
|
||||
}
|
||||
/* 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->flag = flag;
|
||||
dlib_ptr->soname = soname;
|
||||
dlib_ptr->is_link = is_link;
|
||||
/* 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. */
|
||||
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 (entry->path, dlib_ptr->name, dlib_ptr->soname);
|
||||
if (opt_build_cache)
|
||||
add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag);
|
||||
}
|
||||
|
||||
/* Free all resources. */
|
||||
while (dlibs)
|
||||
{
|
||||
dlib_ptr = dlibs;
|
||||
free (dlib_ptr->soname);
|
||||
free (dlib_ptr->name);
|
||||
dlibs = dlibs->next;
|
||||
free (dlib_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Search through all libraries. */
|
||||
static void
|
||||
search_dirs (void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Parse configuration file. */
|
||||
static void
|
||||
parse_conf (const char *filename)
|
||||
{
|
||||
FILE *file;
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
file = fopen (filename, "r");
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
error (0, errno, _("Can't open configuration file %s"), filename);
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
ssize_t n = getline (&line, &len, file);
|
||||
if (n < 0)
|
||||
break;
|
||||
|
||||
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';
|
||||
|
||||
/* If the line is blank it is ignored. */
|
||||
if (line[0] == '\0')
|
||||
continue;
|
||||
|
||||
add_dir (line);
|
||||
} while (!feof (file));
|
||||
|
||||
/* Free buffer and close file. */
|
||||
free (line);
|
||||
fclose (file);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int remaining;
|
||||
|
||||
/* Parse and process arguments. */
|
||||
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
|
||||
|
||||
/* Remaining arguments are additional libraries. */
|
||||
if (remaining != argc)
|
||||
{
|
||||
int i;
|
||||
for (i = remaining; i < argc; ++i)
|
||||
add_dir (argv [i]);
|
||||
}
|
||||
|
||||
if (cache_file == NULL)
|
||||
cache_file = LD_SO_CACHE;
|
||||
|
||||
if (config_file == NULL)
|
||||
config_file = LD_SO_CONF;
|
||||
|
||||
/* Chroot first. */
|
||||
if (opt_chroot)
|
||||
{
|
||||
if (chroot (opt_chroot))
|
||||
/* Report failure and exit program. */
|
||||
error (EXIT_FAILURE, errno, _("Can't chroot to %s"), opt_chroot);
|
||||
/* chroot doesn't change the working directory, let's play safe. */
|
||||
if (chdir ("/"))
|
||||
error (EXIT_FAILURE, errno, _("Can't chdir to /"));
|
||||
}
|
||||
|
||||
if (opt_print_cache)
|
||||
{
|
||||
print_cache (cache_file);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
if (opt_build_cache)
|
||||
init_cache ();
|
||||
|
||||
if (!opt_only_cline)
|
||||
{
|
||||
/* Always add the standard search paths. */
|
||||
add_dir ("/lib");
|
||||
add_dir ("/usr/lib");
|
||||
|
||||
parse_conf (config_file);
|
||||
}
|
||||
|
||||
search_dirs ();
|
||||
|
||||
if (opt_build_cache)
|
||||
save_cache (cache_file);
|
||||
|
||||
return 0;
|
||||
}
|
63
elf/ldconfig.h
Normal file
63
elf/ldconfig.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* Copyright (C) 1999 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 Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _LDCONFIG_H
|
||||
#define _LDCONFIG_H
|
||||
|
||||
#define FLAG_ANY -1
|
||||
#define FLAG_TYPE_MASK 0x00ff
|
||||
#define FLAG_LIBC4 0x0000
|
||||
#define FLAG_ELF 0x0001
|
||||
#define FLAG_ELF_LIBC5 0x0002
|
||||
#define FLAG_ELF_LIBC6 0x0003
|
||||
#define FLAG_REQUIRED_MASK 0xff00
|
||||
#define FLAG_SPARC_LIB64 0x0100
|
||||
|
||||
/* Declared in cache.c. */
|
||||
extern void print_cache (const char *cache_name);
|
||||
|
||||
extern void init_cache (void);
|
||||
|
||||
extern void save_cache (const char *cache_name);
|
||||
|
||||
extern void add_to_cache (const char *path, const char *lib, int flags);
|
||||
|
||||
extern int cache_libcmp (const char *p1, const char *p2);
|
||||
|
||||
|
||||
/* Declared in readlib.c. */
|
||||
extern int process_file (const char *file_name, const char *lib, int *flag,
|
||||
char **soname, int is_link);
|
||||
|
||||
/* Declared in readelflib.c. */
|
||||
extern int process_elf_file (const char *file_name, const char *lib, int *flag,
|
||||
char **soname, void *file_contents);
|
||||
|
||||
|
||||
/* Declared in ldconfig.c. */
|
||||
extern int opt_verbose;
|
||||
|
||||
/* Prototypes for a few program-wide used functions. */
|
||||
extern void *xmalloc (size_t __n);
|
||||
extern void *xcalloc (size_t __n, size_t __size);
|
||||
extern void *xrealloc (void *__p, size_t __n);
|
||||
extern char *xstrdup (const char *__str);
|
||||
|
||||
#endif /* ! _LDCONFIG_H */
|
||||
|
160
elf/readlib.c
Normal file
160
elf/readlib.c
Normal file
@ -0,0 +1,160 @@
|
||||
/* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
|
||||
Jakub Jelinek <jakub@redhat.com>, 1999.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* The code in this file and in readelflib is a heavily simplified
|
||||
version of the readelf program that's part of the current binutils
|
||||
development version. Besides the simplification, it has also been
|
||||
modified to read some other file formats. */
|
||||
|
||||
|
||||
#include <a.out.h>
|
||||
#include <elf.h>
|
||||
#include <error.h>
|
||||
#include <link.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "ldconfig.h"
|
||||
|
||||
#define Elf32_CLASS ELFCLASS32
|
||||
#define Elf64_CLASS ELFCLASS64
|
||||
|
||||
struct known_names
|
||||
{
|
||||
const char *soname;
|
||||
int flag;
|
||||
};
|
||||
|
||||
static struct known_names interpreters [] =
|
||||
{
|
||||
{"/lib/ld-linux.so.2", FLAG_ELF_LIBC6},
|
||||
{"/lib/ld-linux.so.1", FLAG_ELF_LIBC5}
|
||||
};
|
||||
|
||||
static struct known_names known_libs [] =
|
||||
{
|
||||
{"libc.so.6", FLAG_ELF_LIBC6},
|
||||
{"libc.so.5", FLAG_ELF_LIBC5},
|
||||
{"libm.so.6", FLAG_ELF_LIBC6},
|
||||
{"libm.so.5", FLAG_ELF_LIBC5}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Returns 0 if everything is ok, != 0 in case of error. */
|
||||
int
|
||||
process_file (const char *file_name, const char *lib, int *flag, char **soname, int is_link)
|
||||
{
|
||||
FILE *file;
|
||||
struct stat statbuf;
|
||||
void *file_contents;
|
||||
int ret;
|
||||
|
||||
ElfW(Ehdr) *elf_header;
|
||||
struct exec *aout_header;
|
||||
|
||||
ret = 0;
|
||||
*flag = FLAG_ANY;
|
||||
*soname = NULL;
|
||||
|
||||
file = fopen (file_name, "rb");
|
||||
if (file == NULL)
|
||||
{
|
||||
/* No error for stale symlink. */
|
||||
if (is_link && strstr (file_name, ".so.") != NULL)
|
||||
return 1;
|
||||
error (0, 0, _("Input file %s not found.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fstat (fileno (file), &statbuf) < 0)
|
||||
{
|
||||
error (0, 0, _("Cannot fstat file %s.\n"), file_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_contents = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fileno (file), 0);
|
||||
if (file_contents == MAP_FAILED)
|
||||
{
|
||||
error (0, 0, _("Cannot mmap file %s.\n"), file_name);
|
||||
fclose (file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* First check if this is an aout file. */
|
||||
aout_header = (struct exec *) file_contents;
|
||||
if (N_MAGIC (*aout_header) == ZMAGIC
|
||||
|| N_MAGIC (*aout_header) == QMAGIC)
|
||||
{
|
||||
/* Aout files don't have a soname, just return the the name
|
||||
including the major number. */
|
||||
char *copy, *major, *dot;
|
||||
copy = xstrdup (lib);
|
||||
major = strstr (copy, ".so.");
|
||||
if (major)
|
||||
{
|
||||
dot = strstr (major + 4, ".");
|
||||
if (dot)
|
||||
*dot = '\0';
|
||||
}
|
||||
*soname = copy;
|
||||
*flag = FLAG_LIBC4;
|
||||
goto done;
|
||||
}
|
||||
|
||||
elf_header = (ElfW(Ehdr) *) file_contents;
|
||||
if (elf_header->e_ident [EI_MAG0] != ELFMAG0
|
||||
|| elf_header->e_ident [EI_MAG1] != ELFMAG1
|
||||
|| elf_header->e_ident [EI_MAG2] != ELFMAG2
|
||||
|| elf_header->e_ident [EI_MAG3] != ELFMAG3)
|
||||
{
|
||||
/* The file is neither ELF nor aout. Check if it's a linker script,
|
||||
like libc.so - otherwise complain. */
|
||||
int len = statbuf.st_size;
|
||||
/* Only search the beginning of the file. */
|
||||
if (len > 512)
|
||||
len = 512;
|
||||
if (memmem (file_contents, len, "GROUP", 5) == NULL
|
||||
&& memmem (file_contents, len, "GNU ld script", 13) == NULL)
|
||||
error (0, 0, _("%s is not an ELF file - it has the wrong magic bytes at the start.\n"),
|
||||
file_name);
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (process_elf_file (file_name, lib, flag, soname, file_contents))
|
||||
ret = 1;
|
||||
|
||||
done:
|
||||
/* Clean up allocated memory and resources. */
|
||||
munmap (file_contents, statbuf.st_size);
|
||||
fclose (file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Get architecture specific version of process_elf_file. */
|
||||
#include "readelflib.c"
|
||||
|
@ -2237,7 +2237,7 @@ the requested time in the @var{requested_time} parameter is rounded up
|
||||
to the next integer multiple of the actual resolution of the system.
|
||||
|
||||
If the function returns because the time has elapsed the return value is
|
||||
zero. If the function return @math{-1} the global variable @var{errno}
|
||||
zero. If the function returns @math{-1} the global variable @var{errno}
|
||||
is set to the following values:
|
||||
|
||||
@table @code
|
||||
|
180
sysdeps/generic/readelflib.c
Normal file
180
sysdeps/generic/readelflib.c
Normal file
@ -0,0 +1,180 @@
|
||||
/* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
|
||||
Jakub Jelinek <jakub@redhat.com>, 1999.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* This code is a heavily simplified version of the readelf program
|
||||
that's part of the current binutils development version. For architectures
|
||||
which need to handle both 32bit and 64bit ELF libraries, this file is
|
||||
included twice for each arch size. */
|
||||
|
||||
/* Returns 0 if everything is ok, != 0 in case of error. */
|
||||
int
|
||||
process_elf_file (const char *file_name, const char *lib, int *flag, char **soname,
|
||||
void *file_contents)
|
||||
{
|
||||
int i;
|
||||
unsigned int j;
|
||||
int loadaddr;
|
||||
unsigned int dynamic_addr;
|
||||
size_t dynamic_size;
|
||||
char *program_interpreter;
|
||||
|
||||
ElfW(Ehdr) *elf_header;
|
||||
ElfW(Phdr) *elf_pheader, *segment;
|
||||
ElfW(Dyn) *dynamic_segment, *dyn_entry;
|
||||
char *dynamic_strings;
|
||||
|
||||
elf_header = (ElfW(Ehdr) *) file_contents;
|
||||
|
||||
if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
|
||||
{
|
||||
if (opt_verbose)
|
||||
{
|
||||
if (ElfW (CLASS) == ELFCLASS32)
|
||||
error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
|
||||
else if (ElfW (CLASS) == ELFCLASS64)
|
||||
error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
|
||||
else
|
||||
error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (elf_header->e_type != ET_DYN)
|
||||
{
|
||||
error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
|
||||
elf_header->e_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get information from elf program header. */
|
||||
elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
|
||||
|
||||
/* The library is an elf library, now search for soname and
|
||||
libc5/libc6. */
|
||||
*flag = FLAG_ELF;
|
||||
|
||||
loadaddr = -1;
|
||||
dynamic_addr = 0;
|
||||
dynamic_size = 0;
|
||||
program_interpreter = NULL;
|
||||
for (i = 0, segment = elf_pheader;
|
||||
i < elf_header->e_phnum; i++, segment++)
|
||||
{
|
||||
switch (segment->p_type)
|
||||
{
|
||||
case PT_LOAD:
|
||||
if (loadaddr == -1)
|
||||
loadaddr = (segment->p_vaddr & 0xfffff000)
|
||||
- (segment->p_offset & 0xfffff000);
|
||||
break;
|
||||
|
||||
case PT_DYNAMIC:
|
||||
if (dynamic_addr)
|
||||
error (0, 0, _("more than one dynamic segment\n"));
|
||||
|
||||
dynamic_addr = segment->p_offset;
|
||||
dynamic_size = segment->p_filesz;
|
||||
break;
|
||||
case PT_INTERP:
|
||||
program_interpreter = (char *) (file_contents + segment->p_offset);
|
||||
|
||||
/* Check if this is enough to classify the binary. */
|
||||
for (j = 0; j < sizeof (interpreters) / sizeof (interpreters [0]);
|
||||
++j)
|
||||
if (strcmp (program_interpreter, interpreters[j].soname) == 0)
|
||||
{
|
||||
*flag = interpreters[j].flag;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (loadaddr == -1)
|
||||
{
|
||||
/* Very strange. */
|
||||
loadaddr = 0;
|
||||
}
|
||||
|
||||
/* Now we can read the dynamic sections. */
|
||||
if (dynamic_size == 0)
|
||||
return 1;
|
||||
|
||||
dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
|
||||
|
||||
/* Find the string table. */
|
||||
dynamic_strings = NULL;
|
||||
for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
|
||||
++dyn_entry)
|
||||
{
|
||||
if (dyn_entry->d_tag == DT_STRTAB)
|
||||
{
|
||||
dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_strings == NULL)
|
||||
return 1;
|
||||
|
||||
/* Now read the DT_NEEDED and DT_SONAME entries. */
|
||||
for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
|
||||
++dyn_entry)
|
||||
{
|
||||
if (dyn_entry->d_tag == DT_NEEDED || dyn_entry->d_tag == DT_SONAME)
|
||||
{
|
||||
char *name = dynamic_strings + dyn_entry->d_un.d_val;
|
||||
|
||||
if (dyn_entry->d_tag == DT_NEEDED)
|
||||
{
|
||||
|
||||
if (*flag == FLAG_ELF)
|
||||
{
|
||||
/* Check if this is enough to classify the binary. */
|
||||
for (j = 0;
|
||||
j < sizeof (known_libs) / sizeof (known_libs [0]);
|
||||
++j)
|
||||
if (strcmp (name, known_libs [j].soname) == 0)
|
||||
{
|
||||
*flag = known_libs [j].flag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (dyn_entry->d_tag == DT_SONAME)
|
||||
*soname = xstrdup (name);
|
||||
|
||||
/* Do we have everything we need? */
|
||||
if (*soname && *flag != FLAG_ELF)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We reach this point only if the file doesn't contain a DT_SONAME
|
||||
or if we can't classify the library. If it doesn't have a
|
||||
soname, return the name of the library. */
|
||||
if (*soname == NULL)
|
||||
*soname = xstrdup (lib);
|
||||
|
||||
return 0;
|
||||
}
|
57
sysdeps/unix/sysv/linux/sparc/readelflib.c
Normal file
57
sysdeps/unix/sysv/linux/sparc/readelflib.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Andreas Jaeger <aj@suse.de>, 1999 and
|
||||
Jakub Jelinek <jakub@redhat.com>, 1999.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either 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,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
|
||||
int process_elf32_file (const char *file_name, const char *lib, int *flag,
|
||||
char **soname, void *file_contents);
|
||||
int process_elf64_file (const char *file_name, const char *lib, int *flag,
|
||||
char **soname, void *file_contents);
|
||||
|
||||
/* Returns 0 if everything is ok, != 0 in case of error. */
|
||||
int
|
||||
process_elf_file (const char *file_name, const char *lib, int *flag,
|
||||
char **soname, void *file_contents)
|
||||
{
|
||||
ElfW(Ehdr) *elf_header = (ElfW(Ehdr) *) file_contents;
|
||||
int ret;
|
||||
|
||||
if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
|
||||
return process_elf32_file (file_name, lib, flag, soname, file_contents);
|
||||
else
|
||||
{
|
||||
ret = process_elf64_file (file_name, lib, flag, soname, file_contents);
|
||||
/* Sparc 64bit libraries are always libc.so.6+. */
|
||||
if (!ret)
|
||||
*flag = FLAG_SPARC_LIB64|FLAG_ELF_LIBC6;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#undef __ELF_NATIVE_CLASS
|
||||
#undef process_elf_file
|
||||
#define process_elf_file process_elf32_file
|
||||
#define __ELF_NATIVE_CLASS 32
|
||||
#include "sysdeps/generic/readelflib.c"
|
||||
|
||||
#undef __ELF_NATIVE_CLASS
|
||||
#undef process_elf_file
|
||||
#define process_elf_file process_elf64_file
|
||||
#define __ELF_NATIVE_CLASS 64
|
||||
#include "sysdeps/generic/readelflib.c"
|
Loading…
Reference in New Issue
Block a user