2000-05-06  Bruno Haible  <haible@clisp.cons.org>

	* iconv/gconv_open.c (__gconv_open): If __gconv_find_transform
	returned != __GCONV_OK, there is nothing to clean up.

2000-05-06  Bruno Haible  <haible@clisp.cons.org>

	* intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and
	OUTPUT_CHARSET environment variables.

2000-05-06  Andreas Jaeger  <aj@suse.de>

	* sysdeps/generic/dl-cache.h (struct file_entry_new): New.
	(struct cache_file_new): New.
	(struct file_entry): New (moved from cache.c).
	(struct cache_file): New (moved from cache.c).

	* sysdeps/generic/dl-cache.c (SEARCH_CACHE): New macro, broken out
	from _dl_load_cache_lookup.
	(_dl_load_cache_lookup): Move search to SEARCH_CACHE macro, handle
	the different cache formats.
	New variable cache_new for new format.

	* elf/ldconfig.h: Change according to changes in cache.c and
	ldconfig.c; remove cache_libcmp; add opt_format.

	* elf/ldconfig.c: Include "dl-cache.h" and "dl-procinfo.h"; remove
	stuff that's defined in those headers.
	Add hwcap to struct lib_entry.
	(opt_format): New variable to select cache format.
	(options): Add format parameter.
	(is_hwcap): New function.
	(path_hwcap): New function.
	(parse_opt): Handle new format parameter.
	(search_dir): Handle hwcap, search also subdirectories with hwcap.

	* elf/cache.c (_GNU_SOURCE): Removed.  Not needed anymore since
	ldconfig is part of glibc.
	Include dl-cache.h and remove stuff that's defined there.
	(struct cache_entry): Add new member hwcap.
	(print_entry): Print hwcap, cleanup a bit.
	(print_cache): Print new and old formats.
	(compare): Use _dl_cache_libcmp from dl-cache.h; handle hwcap.
	(save_cache): Save new and old formats.
	(add_to_cache): Handle hwcap.

	* sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Moved from here...
	* sysdeps/generic/dl-cache.h (_dl_cache_libcmp): ...to here.
	* sysdeps/generic/dl-cache.c (LD_SO_CACHE): Moved from here...
	* sysdeps/generic/dl-cache.h (LD_SO_CACHE): ...to here.
	* sysdeps/generic/dl-cache.c (CACHEMAGIC): Moved from here...
	* sysdeps/generic/dl-cache.h (CACHEMAGIC): ...to here.

2000-05-05  Bruno Haible  <haible@clisp.cons.org>

	* intl/dcigettext.c (alignof): New macro.
	(_nl_find_msg): Use it instead of __alignof__. Pass correct output
	buffer length to __gconv/iconv. If malloc (freemem_size) fails, set
	freemem_size to 0.

2000-05-05  Bruno Haible  <haible@clisp.cons.org>

	* intl/dcigettext.c (dcigettext): Fix interpretation of tsearch
	return value.
This commit is contained in:
Ulrich Drepper 2000-05-07 21:23:56 +00:00
parent d89d0afad4
commit 45eca4d141
14 changed files with 725 additions and 314 deletions

View File

@ -1,3 +1,68 @@
2000-05-06 Bruno Haible <haible@clisp.cons.org>
* iconv/gconv_open.c (__gconv_open): If __gconv_find_transform
returned != __GCONV_OK, there is nothing to clean up.
2000-05-06 Bruno Haible <haible@clisp.cons.org>
* intl/tst-gettext.c (main): Disable possibly existing LC_CTYPE and
OUTPUT_CHARSET environment variables.
2000-05-06 Andreas Jaeger <aj@suse.de>
* sysdeps/generic/dl-cache.h (struct file_entry_new): New.
(struct cache_file_new): New.
(struct file_entry): New (moved from cache.c).
(struct cache_file): New (moved from cache.c).
* sysdeps/generic/dl-cache.c (SEARCH_CACHE): New macro, broken out
from _dl_load_cache_lookup.
(_dl_load_cache_lookup): Move search to SEARCH_CACHE macro, handle
the different cache formats.
New variable cache_new for new format.
* elf/ldconfig.h: Change according to changes in cache.c and
ldconfig.c; remove cache_libcmp; add opt_format.
* elf/ldconfig.c: Include "dl-cache.h" and "dl-procinfo.h"; remove
stuff that's defined in those headers.
Add hwcap to struct lib_entry.
(opt_format): New variable to select cache format.
(options): Add format parameter.
(is_hwcap): New function.
(path_hwcap): New function.
(parse_opt): Handle new format parameter.
(search_dir): Handle hwcap, search also subdirectories with hwcap.
* elf/cache.c (_GNU_SOURCE): Removed. Not needed anymore since
ldconfig is part of glibc.
Include dl-cache.h and remove stuff that's defined there.
(struct cache_entry): Add new member hwcap.
(print_entry): Print hwcap, cleanup a bit.
(print_cache): Print new and old formats.
(compare): Use _dl_cache_libcmp from dl-cache.h; handle hwcap.
(save_cache): Save new and old formats.
(add_to_cache): Handle hwcap.
* sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Moved from here...
* sysdeps/generic/dl-cache.h (_dl_cache_libcmp): ...to here.
* sysdeps/generic/dl-cache.c (LD_SO_CACHE): Moved from here...
* sysdeps/generic/dl-cache.h (LD_SO_CACHE): ...to here.
* sysdeps/generic/dl-cache.c (CACHEMAGIC): Moved from here...
* sysdeps/generic/dl-cache.h (CACHEMAGIC): ...to here.
2000-05-05 Bruno Haible <haible@clisp.cons.org>
* intl/dcigettext.c (alignof): New macro.
(_nl_find_msg): Use it instead of __alignof__. Pass correct output
buffer length to __gconv/iconv. If malloc (freemem_size) fails, set
freemem_size to 0.
2000-05-05 Bruno Haible <haible@clisp.cons.org>
* intl/dcigettext.c (dcigettext): Fix interpretation of tsearch
return value.
2000-05-06 Ulrich Drepper <drepper@redhat.com>
* intl/dcigettext.c (DCIGETTEXT): Always define local variable `index'.

View File

@ -17,9 +17,6 @@
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>
@ -34,32 +31,18 @@
#include <sys/types.h>
#include "ldconfig.h"
#define CACHEMAGIC "ld.so-1.7.0"
#include "dl-cache.h"
struct cache_entry
{
char *lib;
char *path;
int flags;
struct cache_entry *next;
char *lib; /* Library name. */
char *path; /* Path to find library. */
int flags; /* Flags to indicate kind of library. */
unsigned long int hwcap; /* Important hardware capabilities. */
int bits_hwcap; /* Number of bits set in hwcap. */
struct cache_entry *next; /* Next entry in list. */
};
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;
@ -69,7 +52,7 @@ static const char *flag_descr[] =
/* Print a single entry. */
static void
print_entry (const char *lib, int flag, const char *key)
print_entry (const char *lib, int flag, unsigned long int hwcap, const char *key)
{
printf ("\t%s (", lib);
switch (flag & FLAG_TYPE_MASK)
@ -93,14 +76,17 @@ print_entry (const char *lib, int flag, const char *key)
case 0:
break;
default:
fprintf (stdout, ",%d", flag & FLAG_REQUIRED_MASK);
printf (",%d", flag & FLAG_REQUIRED_MASK);
break;
}
if (hwcap != 0)
printf (", hwcap: 0x%lx", hwcap);
printf (") => %s\n", key);
}
/* Print the whole cache file. */
/* Print the whole cache file, if a file contains the new cache format
hidden in the old one, print the contents of the new format. */
void
print_cache (const char *cache_name)
{
@ -109,7 +95,9 @@ print_cache (const char *cache_name)
int fd;
unsigned int i;
struct cache_file *cache;
struct cache_file_new *cache_new = NULL;
const char *cache_data;
int format = 0;
fd = open (cache_name, O_RDONLY);
if (fd < 0)
@ -128,20 +116,63 @@ print_cache (const char *cache_name)
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];
if (cache_size < sizeof (struct cache_file))
error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
printf (_("%d libs found in cache `%s'\n"), cache->nlibs, cache_name);
if (memcmp (cache->magic, CACHEMAGIC, sizeof CACHEMAGIC - 1))
{
/* This can only be the new format without the old one. */
cache_new = (struct cache_file_new *) cache;
/* 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);
if (memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
|| memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1))
error (EXIT_FAILURE, 0, _("File is not a cache file.\n"));
format = 1;
/* This is where the strings start. */
cache_data = (const char *) cache;
}
else
{
/* This is where the strings start. */
cache_data = (const char *) &cache->libs[cache->nlibs];
/* Check for a new cache embedded in the old format. */
if (cache_size >
(sizeof (struct cache_file)
+ cache->nlibs * sizeof (struct file_entry)
+ sizeof (struct cache_file_new)))
{
cache_new = (struct cache_file_new *) cache_data;
if (!memcmp (cache_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1)
&& !memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1))
format = 1;
}
}
if (format == 0)
{
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, 0,
cache_data + cache->libs[i].value);
}
else if (format == 1)
{
printf (_("%d libs found in cache `%s'\n"), cache_new->nlibs, cache_name);
/* Print everything. */
for (i = 0; i < cache_new->nlibs; i++)
print_entry (cache_data + cache_new->libs[i].key,
cache_new->libs[i].flags,
cache_new->libs[i].hwcap,
cache_data + cache_new->libs[i].value);
}
/* Cleanup. */
munmap (cache, cache_size);
close (fd);
@ -155,45 +186,6 @@ init_cache (void)
}
/* 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)
@ -201,80 +193,142 @@ 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);
res = _dl_cache_libcmp (e2->lib, e1->lib);
if (res == 0)
{
if (e1->flags < e2->flags)
return 1;
else if (e1->flags > e2->flags)
return -1;
/* Sort by most specific hwcap. */
else if (e2->bits_hwcap > e1->bits_hwcap)
return 1;
else if (e2->bits_hwcap < e1->bits_hwcap)
return -1;
else if (e2->hwcap > e1->hwcap)
return 1;
else if (e2->hwcap < e1->hwcap)
return -1;
}
return res;
}
/* Save the contents of the cache. */
void
save_cache (const char *cache_name)
{
struct cache_entry *entry;
int i, fd;
int fd, idx_old, idx_new;
size_t total_strlen, len;
char *strings, *str, *temp_name;
struct cache_file *file_entries;
size_t file_entries_size;
struct cache_file *file_entries = NULL;
struct cache_file_new *file_entries_new = NULL;
size_t file_entries_size = 0;
size_t file_entries_new_size = 0;
unsigned int str_offset;
/* Number of cache entries. */
int cache_entry_count = 0;
/* Number of normal cache entries. */
int cache_entry_old_count = 0;
/* The cache entries are sorted already, save them in this order. */
/* Count the length of all strings. */
/* The old format doesn't contain hwcap entries and doesn't contain
libraries in subdirectories with hwcaps entries. Count therefore
also all entries with hwcap == 0. */
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;
if (entry->hwcap == 0)
++cache_entry_old_count;
}
/* Create the on disk cache structure. */
/* First an array for all strings. */
strings = (char *)xmalloc (total_strlen + 1);
strings = (char *)xmalloc (total_strlen);
/* 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)
if (opt_format != 2)
{
/* And the list of all entries in the old format. */
file_entries_size = sizeof (struct cache_file)
+ cache_entry_old_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_old_count;
}
if (opt_format != 0)
{
/* And the list of all entries in the new format. */
file_entries_new_size = sizeof (struct cache_file_new)
+ cache_entry_count * sizeof (struct file_entry_new);
file_entries_new = (struct cache_file_new *) xmalloc (file_entries_new_size);
/* Fill in the header. */
memset (file_entries_new, 0, sizeof (struct cache_file_new));
memcpy (file_entries_new->magic, CACHEMAGIC_NEW, sizeof CACHEMAGIC_NEW - 1);
memcpy (file_entries_new->version, CACHE_VERSION, sizeof CACHE_VERSION - 1);
file_entries_new->nlibs = cache_entry_count;
file_entries_new->len_strings = total_strlen;
}
/* If we have both formats, we hide the new format in the strings
table, we have to adjust all string indices for this so that
old libc5/glibc 2 dynamic linkers just ignore them. */
if (opt_format == 1)
str_offset = file_entries_new_size;
else
str_offset = 0;
str = strings;
for (idx_old = 0, idx_new = 0, entry = entries; entry != NULL;
entry = entry->next, ++idx_new)
{
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;
if (opt_format != 2)
{
file_entries->libs[idx_old].flags = entry->flags;
/* XXX: Actually we can optimize here and remove duplicates. */
file_entries->libs[idx_old].key = str_offset;
}
if (opt_format != 0)
{
/* We could subtract file_entries_new_size from str_offset -
not doing so makes the code easier, the string table
always begins at the beginning of the the new cache
struct. */
file_entries_new->libs[idx_new].flags = entry->flags;
file_entries_new->libs[idx_new].hwcap = entry->hwcap;
file_entries_new->libs[idx_new].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;
if (opt_format != 2)
file_entries->libs[idx_old].value = str_offset;
if (opt_format != 0)
file_entries_new->libs[idx_new].value = str_offset;
len = strlen (entry->path);
str = stpcpy (str, entry->path);
/* Account the final NUL. */
++str;
str_offset += len + 1;
/* Ignore entries with hwcap for old format. */
if (entry->hwcap == 0)
++idx_old;
}
assert (str_offset == total_strlen);
/* Write out the cache. */
@ -293,8 +347,17 @@ save_cache (const char *cache_name)
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 (opt_format != 2)
{
if (write (fd, file_entries, file_entries_size) != (ssize_t)file_entries_size)
error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
}
if (opt_format != 0)
{
if (write (fd, file_entries_new, file_entries_new_size)
!= (ssize_t)file_entries_new_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."));
@ -325,13 +388,15 @@ save_cache (const char *cache_name)
}
}
/* Add one library to the cache. */
void
add_to_cache (const char *path, const char *lib, int flags)
add_to_cache (const char *path, const char *lib, int flags,
unsigned long int hwcap)
{
struct cache_entry *new_entry, *ptr, *prev;
char *full_path;
int len;
int len, i;
new_entry = (struct cache_entry *) xmalloc (sizeof (struct cache_entry));
@ -343,6 +408,14 @@ add_to_cache (const char *path, const char *lib, int flags)
new_entry->lib = xstrdup (lib);
new_entry->path = full_path;
new_entry->flags = flags;
new_entry->hwcap = hwcap;
new_entry->bits_hwcap = 0;
/* Count the number of bits set in the masked value. */
for (i = 0; (~((1UL << i) - 1) & hwcap) != 0; ++i)
if ((hwcap & (1UL << i)) != 0)
++new_entry->bits_hwcap;
/* Keep the list sorted - search for right place to insert. */
ptr = entries;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1999 Free Software Foundation, Inc.
/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@ -32,10 +32,12 @@
#include <sys/types.h>
#include "ldconfig.h"
#include "dl-cache.h"
#ifndef LD_SO_CACHE
# define LD_SO_CACHE "/etc/ld.so.cache"
#endif
/* We don't need this here - silence the compiler. */
#define _dl_sysdep_message(string, args...) do {} while (0);
#include "dl-procinfo.h"
#ifndef LD_SO_CONF
# define LD_SO_CONF "/etc/ld.so.conf"
@ -49,6 +51,7 @@
struct lib_entry
{
int flags;
unsigned long int hwcap;
char *lib;
char *path;
};
@ -63,7 +66,7 @@ static const struct
{"libc5", FLAG_ELF_LIBC5},
{"libc6", FLAG_ELF_LIBC6},
{"glibc2", FLAG_ELF_LIBC6}
};
};
/* List of directories to handle. */
@ -85,6 +88,10 @@ static int opt_print_cache = 0;
/* Be verbose. */
int opt_verbose = 0;
/* Format to support. */
/* 0: only libc5/glibc2; 1: both; 2: only glibc 2.2. */
int opt_format = 1;
/* Build cache. */
static int opt_build_cache = 1;
@ -123,6 +130,7 @@ static const struct argp_option options[] =
{ 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, 'l', NULL, 0, N_("Manually link individual libraries."), 0},
{ "format", 'c', "FORMAT", 0, N_("Format to use: new, old or compat (default)"), 0},
{ NULL, 0, NULL, 0, NULL, 0 }
};
@ -138,7 +146,53 @@ static struct argp argp =
options, parse_opt, NULL, doc, NULL, NULL, NULL
};
/* Check if string corresponds to an important hardware capability. */
static int
is_hwcap (const char *name)
{
int hwcap_idx = _dl_string_hwcap (name);
if (hwcap_idx != -1 && ((1 << hwcap_idx) & HWCAP_IMPORTANT))
return 1;
return 0;
}
/* Get hwcap encoding of path. */
static unsigned long int
path_hwcap (const char *path)
{
char *str = xstrdup (path);
char *ptr;
unsigned long int hwcap = 0;
unsigned long int h;
size_t len;
len = strlen (str);
if (str[len] == '/')
str[len] = '\0';
/* Search pathname from the end and check for hwcap strings. */
for (;;)
{
ptr = strrchr (str, '/');
if (ptr == NULL)
break;
h = _dl_string_hwcap (ptr+1);
if (h == -1)
break;
hwcap += 1 << h;
/* Search the next part of the path. */
*ptr = '\0';
}
free (str);
return hwcap;
}
/* Handle program arguments. */
static error_t
@ -174,6 +228,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'X':
opt_link = 0;
break;
case 'c':
if (strcmp (arg, "old") == 0)
opt_format = 0;
else if (strcmp (arg, "compat") == 0)
opt_format = 1;
else if (strcmp (arg, "new") == 0)
opt_format = 2;
break;
default:
return ARGP_ERR_UNKNOWN;
}
@ -190,7 +252,7 @@ print_version (FILE *stream, struct argp_state *state)
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");
"), "2000");
fprintf (stream, gettext ("Written by %s.\n"),
"Andreas Jaeger");
}
@ -202,10 +264,10 @@ 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, '=');
@ -235,7 +297,7 @@ add_dir (const char *line)
entry->path [i] = '\0';
--i;
}
ptr = dir_entries;
prev = ptr;
while (ptr != NULL)
@ -270,7 +332,7 @@ create_links (const char *path, const char *libname, const char *soname)
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);
@ -405,7 +467,7 @@ manual_link (char *library)
- 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.
@ -416,7 +478,7 @@ manual_link (char *library)
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.
@ -424,7 +486,7 @@ manual_link (char *library)
libxy.so.1.1. */
/* Information for one library. */
struct dlib_entry
struct dlib_entry
{
char *name;
char *soname;
@ -446,12 +508,18 @@ search_dir (const struct dir_entry *entry)
int nchars;
struct stat stat_buf;
int is_link;
unsigned long int hwcap = path_hwcap (entry->path);
dlibs = NULL;
if (opt_verbose)
printf ("%s:\n", entry->path);
{
if (hwcap != 0)
printf ("%s: (hwcap: 0x%lx)\n", entry->path, hwcap);
else
printf ("%s:\n", entry->path);
}
dir = opendir (entry->path);
if (dir == NULL)
{
@ -459,7 +527,7 @@ search_dir (const struct dir_entry *entry)
error (0, errno, _("Can't open directory %s"), entry->path);
return;
}
while ((direntry = readdir (dir)) != NULL)
{
@ -468,15 +536,17 @@ search_dir (const struct dir_entry *entry)
/* We only look at links and regular files. */
if (direntry->d_type != DT_UNKNOWN
&& direntry->d_type != DT_LNK
&& direntry->d_type != DT_REG)
&& direntry->d_type != DT_REG
&& direntry->d_type != DT_DIR)
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)
/* Does this file look like a shared library or is it a hwcap
subdirectory? The dynamic linker is also considered as
shared library. */
if (((strncmp (direntry->d_name, "lib", 3) != 0
&& strncmp (direntry->d_name, "ld-", 3) != 0)
|| strstr (direntry->d_name, ".so") == NULL)
&& !is_hwcap (direntry->d_name))
continue;
nchars = snprintf (buf, sizeof (buf), "%s/%s", entry->path,
direntry->d_name);
@ -492,6 +562,16 @@ search_dir (const struct dir_entry *entry)
error (0, errno, _("Can't lstat %s"), buf);
continue;
}
else if (S_ISDIR (stat_buf.st_mode) && is_hwcap (direntry->d_name))
{
/* Handle subdirectory also, make a recursive call. */
struct dir_entry new_entry;
new_entry.path = buf;
new_entry.flag = entry->flag;
new_entry.next = NULL;
search_dir (&new_entry);
continue;
}
else if (!S_ISREG (stat_buf.st_mode) && !S_ISLNK (stat_buf.st_mode))
continue;
@ -506,7 +586,7 @@ search_dir (const struct dir_entry *entry)
free (soname);
soname = xstrdup (direntry->d_name);
}
if (flag == FLAG_ELF
&& (entry->flag == FLAG_ELF_LIBC5
|| entry->flag == FLAG_ELF_LIBC6))
@ -524,7 +604,7 @@ search_dir (const struct dir_entry *entry)
&& 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)
{
@ -535,7 +615,7 @@ search_dir (const struct dir_entry *entry)
is newer. */
if ((!is_link && dlib_ptr->is_link)
|| (is_link == dlib_ptr->is_link
&& cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
&& _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
{
/* It's newer - add it. */
/* Flag should be the same - sanity check. */
@ -586,11 +666,11 @@ search_dir (const struct dir_entry *entry)
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);
add_to_cache (entry->path, dlib_ptr->soname, dlib_ptr->flag, hwcap);
}
/* Free all resources. */
while (dlibs)
while (dlibs)
{
dlib_ptr = dlibs;
free (dlib_ptr->soname);
@ -627,7 +707,7 @@ parse_conf (const char *filename)
FILE *file;
char *line = NULL;
size_t len = 0;
file = fopen (filename, "r");
if (file == NULL)
@ -667,7 +747,7 @@ int
main (int argc, char **argv)
{
int remaining;
/* Parse and process arguments. */
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
@ -685,7 +765,7 @@ main (int argc, char **argv)
if (config_file == NULL)
config_file = LD_SO_CONF;
/* Chroot first. */
if (opt_chroot)
{
@ -713,8 +793,8 @@ main (int argc, char **argv)
exit (0);
}
if (opt_build_cache)
init_cache ();
@ -726,7 +806,7 @@ main (int argc, char **argv)
parse_conf (config_file);
}
search_dirs ();
if (opt_build_cache)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1999 Free Software Foundation, Inc.
/* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Andreas Jaeger <aj@suse.de>, 1999.
@ -37,10 +37,8 @@ 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);
extern void add_to_cache (const char *path, const char *lib, int flags,
unsigned long int hwcap);
/* Declared in readlib.c. */
extern int process_file (const char *file_name, const char *lib, int *flag,
@ -54,6 +52,8 @@ extern int process_elf_file (const char *file_name, const char *lib, int *flag,
/* Declared in ldconfig.c. */
extern int opt_verbose;
extern int opt_format;
/* Prototypes for a few program-wide used functions. */
extern void *xmalloc (size_t __n);
extern void *xcalloc (size_t __n, size_t __size);
@ -61,4 +61,3 @@ extern void *xrealloc (void *__p, size_t __n);
extern char *xstrdup (const char *__str);
#endif /* ! _LDCONFIG_H */

View File

@ -93,25 +93,25 @@ __gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
result->__data[cnt].__internal_use = 0;
result->__data[cnt].__statep = &result->__data[cnt].__state;
}
}
if (res != __GCONV_OK)
{
/* Something went wrong. Free all the resources. */
int serrno = errno;
if (result != NULL)
if (res != __GCONV_OK)
{
while (cnt-- > 0)
free (result->__data[cnt].__outbuf);
/* Something went wrong. Free all the resources. */
int serrno = errno;
free (result);
result = NULL;
if (result != NULL)
{
while (cnt-- > 0)
free (result->__data[cnt].__outbuf);
free (result);
result = NULL;
}
__gconv_close_transform (steps, nsteps);
__set_errno (serrno);
}
__gconv_close_transform (steps, nsteps);
__set_errno (serrno);
}
*handle = result;

View File

@ -110,6 +110,14 @@ void free ();
# define __libc_rwlock_unlock(NAME)
#endif
/* Alignment of types. */
#if defined __GNUC__ && __GNUC__ >= 2
# define alignof(TYPE) __alignof__ (TYPE)
#else
# define alignof(TYPE) \
((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
#endif
/* @@ end of prolog @@ */
#ifdef _LIBC
@ -785,20 +793,24 @@ _nl_find_msg (domain_file, msgid, index)
resultlen = p - result;
}
inbuf = result;
outbuf = freemem + 4;
__libc_lock_lock (lock);
inbuf = result;
outbuf = freemem + sizeof (nls_uint32);
while (1)
{
# ifdef _LIBC
size_t non_reversible;
int res;
if (freemem_size < 4)
goto resize_freemem;
res = __gconv (domain->conv,
&inbuf, inbuf + resultlen,
&outbuf, outbuf + freemem_size,
&outbuf,
outbuf + freemem_size - sizeof (nls_uint32),
&non_reversible);
if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
@ -816,8 +828,12 @@ _nl_find_msg (domain_file, msgid, index)
const char *inptr = (const char *) inbuf;
size_t inleft = resultlen;
char *outptr = (char *) outbuf;
size_t outleft = freemem_size;
size_t outleft;
if (freemem_size < 4)
goto resize_freemem;
outleft = freemem_size - 4;
if (iconv (domain->conv, &inptr, &inleft, &outptr, &outleft)
!= (size_t) (-1))
{
@ -832,6 +848,7 @@ _nl_find_msg (domain_file, msgid, index)
# endif
# endif
resize_freemem:
/* We must resize the buffer. */
freemem_size = 2 * freemem_size;
if (freemem_size < 4064)
@ -839,11 +856,12 @@ _nl_find_msg (domain_file, msgid, index)
freemem = (char *) malloc (freemem_size);
if (__builtin_expect (freemem == NULL, 0))
{
freemem_size = 0;
__libc_lock_unlock (lock);
goto converted;
}
outbuf = freemem + 4;
outbuf = freemem + sizeof (nls_uint32);
}
/* We have now in our buffer a converted string. Put this
@ -853,15 +871,15 @@ _nl_find_msg (domain_file, msgid, index)
/* Shrink freemem, but keep it aligned. */
freemem_size -= outbuf - freemem;
freemem = outbuf;
freemem += freemem_size & (__alignof__ (nls_uint32) - 1);
freemem_size = freemem_size & ~ (__alignof__ (nls_uint32) - 1);
freemem += freemem_size & (alignof (nls_uint32) - 1);
freemem_size = freemem_size & ~ (alignof (nls_uint32) - 1);
__libc_lock_unlock (lock);
}
/* Now domain->conv_tab[act] contains the translation of at least
the variants 0 .. INDEX. */
result = domain->conv_tab[act] + 4;
result = domain->conv_tab[act] + sizeof (nls_uint32);
}
converted:

View File

@ -68,7 +68,9 @@ main (int argc, char *argv[])
setenv ("LANGUAGE", "existing-locale", 1);
setenv ("LC_ALL", "non-existing-locale", 1);
setenv ("LC_MESSAGES", "non-existing-locale", 1);
setenv ("LC_CTYPE", "non-existing-locale", 1);
setenv ("LANG", "non-existing-locale", 1);
unsetenv ("OUTPUT_CHARSET");
/* This is the name of the existing domain with a catalog for the
LC_MESSAGES category. */
textdomain ("existing-domain");

View File

@ -0,0 +1,40 @@
/* This is a test of the special shutdown that occurs
when all threads, including the main one, call
pthread_exit(). It demonstrates that atexit
handlers are properly called, and that the
output is properly flushed even when stdout is
redirected to a file, and therefore fully buffered. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NTHREADS 20 /* number of threads */
static void *thread(void *arg)
{
printf("thread terminating\n");
return 0;
}
void cleanup(void)
{
printf("atexit handler called\n");
}
int main(void)
{
int i;
atexit(cleanup);
for (i = 0; i < NTHREADS; i++) {
pthread_t id;
if (pthread_create(&id, 0, thread, 0) != 0) {
fprintf(stderr, "pthread_create failed\n");
abort();
}
}
pthread_exit(0);
}

View File

@ -38,7 +38,7 @@ libpthread-routines := attr cancel condvar join manager mutex ptfork \
oldsemaphore events getcpuclockid
vpath %.c Examples
tests = ex1 ex2 ex3 ex4 ex5 ex6
tests = ex1 ex2 ex3 ex4 ex5 ex6 ex7
include ../Rules
@ -66,3 +66,4 @@ $(objpfx)ex3: $(libpthread)
$(objpfx)ex4: $(libpthread)
$(objpfx)ex5: $(libpthread)
$(objpfx)ex6: $(libpthread)
$(objpfx)ex7: $(libpthread)

View File

@ -199,7 +199,7 @@ struct pthread_request {
pthread_descr req_thread; /* Thread doing the request */
enum { /* Request kind */
REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT,
REQ_POST, REQ_DEBUG
REQ_POST, REQ_DEBUG, REQ_KICK
} req_kind;
union { /* Arguments for request */
struct { /* For REQ_CREATE: */

View File

@ -73,9 +73,13 @@ void pthread_exit(void * retval)
request.req_kind = REQ_MAIN_THREAD_EXIT;
__libc_write(__pthread_manager_request, (char *)&request, sizeof(request));
suspend(self);
/* Main thread flushes stdio streams and runs atexit functions.
It also calls a handler within LinuxThreads which sends a process exit
request to the thread manager. */
exit(0);
}
/* Exit the process (but don't flush stdio streams, and don't run
atexit functions). */
/* Threads other than the main one terminate without flushing stdio streams
or running atexit functions. */
_exit(0);
}

View File

@ -162,13 +162,22 @@ int __pthread_manager(void *arg)
case REQ_PROCESS_EXIT:
pthread_handle_exit(request.req_thread,
request.req_args.exit.code);
/* NOTREACHED */
break;
case REQ_MAIN_THREAD_EXIT:
main_thread_exiting = 1;
/* Reap children in case all other threads died and the signal handler
went off before we set main_thread_exiting to 1, and therefore did
not do REQ_KICK. */
pthread_reap_children();
if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
restart(__pthread_main_thread);
return 0;
}
/* The main thread will now call exit() which will trigger an
__on_exit handler, which in turn will send REQ_PROCESS_EXIT
to the thread manager. In case you are wondering how the
manager terminates from its loop here. */
}
break;
case REQ_POST:
__new_sem_post(request.req_args.post);
@ -179,6 +188,10 @@ int __pthread_manager(void *arg)
if (__pthread_threads_debug && __pthread_sig_debug > 0)
raise(__pthread_sig_debug);
break;
case REQ_KICK:
/* This is just a prod to get the manager to reap some
threads right away, avoiding a potential delay at shutdown. */
break;
}
}
}
@ -591,7 +604,7 @@ static void pthread_exited(pid_t pid)
if (main_thread_exiting &&
__pthread_main_thread->p_nextlive == __pthread_main_thread) {
restart(__pthread_main_thread);
_exit(0);
/* Same logic as REQ_MAIN_THREAD_EXIT. */
}
}
@ -685,7 +698,22 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
void __pthread_manager_sighandler(int sig)
{
int kick_manager = terminated_children == 0 && main_thread_exiting;
terminated_children = 1;
/* If the main thread is terminating, kick the thread manager loop
each time some threads terminate. This eliminates a two second
shutdown delay caused by the thread manager sleeping in the
call to __poll(). Instead, the thread manager is kicked into
action, reaps the outstanding threads and resumes the main thread
so that it can complete the shutdown. */
if (kick_manager) {
struct pthread_request request;
request.req_thread = 0;
request.req_kind = REQ_KICK;
__libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
}
}
/* Adjust priority of thread manager so that it always run at a priority

View File

@ -22,31 +22,16 @@
#include <sys/mman.h>
#include <dl-cache.h>
/* System-dependent function to read a file's whole contents
in the most convenient manner available. */
extern void *_dl_sysdep_read_whole_file (const char *filename,
size_t *filesize_ptr,
int mmap_prot);
#ifndef LD_SO_CACHE
# define LD_SO_CACHE "/etc/ld.so.cache"
#endif
#define CACHEMAGIC "ld.so-1.7.0"
struct cache_file
{
char magic[sizeof CACHEMAGIC - 1];
unsigned int nlibs;
struct
{
int flags; /* This is 1 for an ELF library. */
unsigned int key, value; /* String table indices. */
} libs[0];
};
/* This is the starting address and the size of the mmap()ed file. */
static struct cache_file *cache;
static struct cache_file_new *cache_new;
static size_t cachesize;
/* 1 if cache_data + PTR points into the cache. */
@ -56,45 +41,100 @@ static size_t cachesize;
binaries. */
int _dl_correct_cache_id = _DL_CACHE_DEFAULT_ID;
/* Helper function which must match the one in ldconfig, so that
we rely on the same sort order. */
static int
_dl_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;
#define SEARCH_CACHE(cache) \
/* We use binary search since the table is sorted in the cache file. \
The first matching entry in the table is returned. \
It is important to use the same algorithm as used while generating \
the cache file. */ \
do \
{ \
left = 0; \
right = cache->nlibs - 1; \
middle = (left + right) / 2; \
cmpres = 1; \
\
while (left <= right) \
{ \
/* Make sure string table indices are not bogus before using \
them. */ \
if (! _dl_cache_verify_ptr (cache->libs[middle].key)) \
{ \
cmpres = 1; \
break; \
} \
\
/* Actually compare the entry with the key. */ \
cmpres = _dl_cache_libcmp (name, \
cache_data + cache->libs[middle].key); \
if (cmpres == 0) \
/* Found it. */ \
break; \
\
if (cmpres < 0) \
left = middle + 1; \
else \
right = middle - 1; \
\
middle = (left + right) / 2; \
} \
\
if (cmpres == 0) \
{ \
/* LEFT now marks the last entry for which we know the name is \
correct. */ \
left = middle; \
\
/* There might be entries with this name before the one we \
found. So we have to find the beginning. */ \
while (middle > 0 \
/* Make sure string table indices are not bogus before \
using them. */ \
&& _dl_cache_verify_ptr (cache->libs[middle - 1].key) \
/* Actually compare the entry. */ \
&& (_dl_cache_libcmp (name, \
cache_data \
+ cache->libs[middle - 1].key) \
== 0)) \
--middle; \
\
do \
{ \
int flags; \
\
/* Only perform the name test if necessary. */ \
if (middle > left \
/* We haven't seen this string so far. Test whether the \
index is ok and whether the name matches. Otherwise \
we are done. */ \
&& (! _dl_cache_verify_ptr (cache->libs[middle].key) \
|| (_dl_cache_libcmp (name, \
cache_data \
+ cache->libs[middle].key) \
!= 0))) \
break; \
\
flags = cache->libs[middle].flags; \
if (_dl_cache_check_flags (flags) \
&& _dl_cache_verify_ptr (cache->libs[middle].value)) \
{ \
if (best == NULL || flags == _dl_correct_cache_id) \
{ \
HWCAP_CHECK; \
best = cache_data + cache->libs[middle].value; \
\
if (flags == _dl_correct_cache_id) \
/* We've found an exact match for the shared \
object and no general `ELF' release. Stop \
searching. */ \
break; \
} \
} \
} \
while (++middle <= right); \
} \
} \
while (0)
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;
}
/* Look up NAME in ld.so.cache and return the file name stored there,
@ -117,10 +157,38 @@ _dl_load_cache_lookup (const char *name)
/* Read the contents of the file. */
void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize,
PROT_READ);
/* We can handle three different cache file formats here:
- the old libc5/glibc2.0/2.1 format
- the old format with the new format in it
- only the new format
The following checks if the cache contains any of these formats. */
if (file && cachesize > sizeof *cache &&
!memcmp (file, CACHEMAGIC, sizeof CACHEMAGIC - 1))
/* Looks ok. */
cache = file;
{
/* Looks ok. */
cache = file;
/* Check for new version. */
cache_new = (struct cache_file_new *) &cache->libs[cache->nlibs];
if (cachesize <
(sizeof (struct cache_file) + cache->nlibs * sizeof (struct file_entry)
+ sizeof (struct cache_file_new))
|| memcmp (cache_new->magic, CACHEMAGIC_NEW,
sizeof CACHEMAGIC_NEW - 1)
|| memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1))
cache_new = (void *) -1;
}
else if (file && cachesize > sizeof *cache_new)
{
cache_new = (struct cache_file_new *) file;
if (memcmp (cache_new->magic, CACHEMAGIC_NEW,
sizeof CACHEMAGIC_NEW - 1)
|| memcmp (cache_new->version, CACHE_VERSION,
sizeof CACHE_VERSION - 1))
cache_new = (void *) -1;
}
else
{
if (file)
@ -139,88 +207,23 @@ _dl_load_cache_lookup (const char *name)
best = NULL;
/* We use binary search since the table is sorted in the cache file.
It is important to use the same algorithm as used while generating
the cache file. */
left = 0;
right = cache->nlibs - 1;
middle = (left + right) / 2;
cmpres = 1;
while (left <= right)
if (cache_new != (void *) -1)
{
/* Make sure string table indices are not bogus before using them. */
if (! _dl_cache_verify_ptr (cache->libs[middle].key))
{
cmpres = 1;
break;
}
/* This file ends in static libraries where we don't have a hwcap. */
unsigned long int *hwcap;
weak_extern (_dl_hwcap);
/* Actually compare the entry with the key. */
cmpres = _dl_cache_libcmp (name, cache_data + cache->libs[middle].key);
if (cmpres == 0)
/* Found it. */
break;
hwcap = &_dl_hwcap;
if (cmpres < 0)
left = middle + 1;
else
right = middle - 1;
middle = (left + right) / 2;
}
if (cmpres == 0)
{
/* LEFT now marks the last entry for which we know the name is
correct. */
left = middle;
/* There might be entries with this name before the one we
found. So we have to find the beginning. */
while (middle > 0
/* Make sure string table indices are not bogus before
using them. */
&& _dl_cache_verify_ptr (cache->libs[middle - 1].key)
/* Actually compare the entry. */
&& (_dl_cache_libcmp (name,
cache_data + cache->libs[middle - 1].key)
== 0))
--middle;
do
{
int flags;
/* Only perform the name test if necessary. */
if (middle > left
/* We haven't seen this string so far. Test whether the
index is ok and whether the name matches. Otherwise
we are done. */
&& (! _dl_cache_verify_ptr (cache->libs[middle].key)
|| (_dl_cache_libcmp (name,
cache_data + cache->libs[middle].key)
!= 0)))
break;
flags = cache->libs[middle].flags;
if (_dl_cache_check_flags (flags)
&& _dl_cache_verify_ptr (cache->libs[middle].value))
{
if (best == NULL || flags == _dl_correct_cache_id)
{
best = cache_data + cache->libs[middle].value;
if (flags == _dl_correct_cache_id)
/* We've found an exact match for the shared
object and no general `ELF' release. Stop
searching. */
break;
}
}
}
while (++middle <= right);
#define HWCAP_CHECK \
if (hwcap && (cache_new->libs[middle].hwcap & *hwcap) > _dl_hwcap) \
continue
SEARCH_CACHE (cache_new);
}
else
#undef HWCAP_CHECK
#define HWCAP_CHECK do {} while (0)
SEARCH_CACHE (cache);
/* Print our result if wanted. */
if (_dl_debug_libs && best != NULL)

View File

@ -1,5 +1,5 @@
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
Copyright (C) 1999 Free Software Foundation, Inc.
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -21,3 +21,101 @@
#define _dl_cache_check_flags(flags) \
((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID)
#ifndef LD_SO_CACHE
# define LD_SO_CACHE "/etc/ld.so.cache"
#endif
#define CACHEMAGIC "ld.so-1.7.0"
/* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another
format has been added in a compatible way:
The beginning of the string table is used for the new table:
old_magic
nlibs
libs[0]
...
libs[nlibs-1]
new magic
newnlibs
...
newlibs[0]
...
newlibs[newnlibs-1]
string 1
string 2
...
*/
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];
};
#define CACHEMAGIC_NEW "glibc-ld.so.cache"
#define CACHE_VERSION "1.0"
struct file_entry_new
{
int flags; /* This is 1 for an ELF library. */
unsigned int key, value; /* String table indices. */
unsigned long hwcap; /* Hwcap entry. */
};
struct cache_file_new
{
char magic[sizeof CACHEMAGIC_NEW - 1];
char version[sizeof CACHE_VERSION - 1];
unsigned int nlibs; /* Number of entries. */
unsigned int len_strings; /* Size of string table. */
unsigned int unused[4]; /* Leave space for future extensions. */
struct file_entry_new libs[0]; /* Entries describing libraries. */
/* After this the string table of size len_strings is found. */
};
static int
_dl_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;
}