echo " \"$$dir\","; \
done;) > $@T
mv -f $@T $@
-$(objpfx)rtldtbl.h: Makefile
+$(objpfx)rtldtbl.h: Makefile genrtldtbl.awk
$(make-target-directory)
echo "$(default-rpath)" | awk -f genrtldtbl.awk > $@T
mv -f $@T $@
size_t _dl_pagesize;
+/* Arguments passed to the dynamic linker. */
+extern char **_dl_argv;
+
extern const char *_dl_platform;
extern size_t _dl_platformlen;
static inline struct r_search_path_elem **
fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
- const char **trusted)
+ const char **trusted, const char *what, const char *where)
{
char *cp;
size_t nelems = 0;
max_dirnamelen = dirp->dirnamelen;
}
+ dirp->what = what;
+ dirp->where = where;
+
dirp->next = all_dirs;
all_dirs = dirp;
static struct r_search_path_elem **
-decompose_rpath (const char *rpath, size_t additional_room)
+decompose_rpath (const char *rpath, size_t additional_room,
+ const char *what, const char *where)
{
/* Make a copy we can work with. */
char *copy = strdupa (rpath);
if (result == NULL)
_dl_signal_error (ENOMEM, NULL, "cannot create cache for search path");
- return fillin_rpath (copy, result, ":", NULL);
+ return fillin_rpath (copy, result, ":", NULL, what, where);
}
decompose_rpath ((const char *)
(l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val),
- nllp);
+ nllp, "RPATH", l->l_name);
}
else
{
/* We need to take care that the LD_LIBRARY_PATH environment
variable can contain a semicolon. */
(void) fillin_rpath (copy, result, ":;",
- __libc_enable_secure ? trusted_dirs : NULL);
+ __libc_enable_secure ? trusted_dirs : NULL,
+ "LD_LIBRARY_PATH", NULL);
}
}
else
"cannot create cache for search path");
(void) fillin_rpath (local_strdup (llp), fake_path_list, ":;",
- __libc_enable_secure ? trusted_dirs : NULL);
+ __libc_enable_secure ? trusted_dirs : NULL,
+ "LD_LIBRARY_PATH", NULL);
}
}
if (max_dirnamelen < relem->dirnamelen)
max_dirnamelen = relem->dirnamelen;
}
+
+ relem->what = "system search path";
+ relem->where = NULL;
}
}
return l;
}
\f
+/* Print search path. */
+static void
+print_search_path (struct r_search_path_elem **list,
+ const char *what, const char *name)
+{
+ int first = 1;
+
+ _dl_sysdep_message ("\t search path=", NULL);
+
+ while (*list != NULL && (*list)->what == what) /* Yes, ==. */
+ {
+ char *buf = strdupa ((*list)->dirname);
+
+ if ((*list)->machdirstatus != nonexisting)
+ {
+ buf[(*list)->machdirnamelen - 1] = '\0';
+ _dl_sysdep_message (first ? "" : ":", buf, NULL);
+ first = 0;
+ }
+ if ((*list)->dirstatus != nonexisting)
+ {
+ buf[(*list)->dirnamelen - 1] = '\0';
+ _dl_sysdep_message (first ? "" : ":", buf, NULL);
+ first = 0;
+ }
+ ++list;
+ }
+
+ if (name != NULL)
+ _dl_sysdep_message ("\t\t(", what, " from file ",
+ name[0] ? name : _dl_argv[0], ")\n", NULL);
+ else
+ _dl_sysdep_message ("\t\t(", what, ")\n", NULL);
+}
+\f
/* Try to open NAME in one of the directories in DIRS.
Return the fd, or -1. If successful, fill in *REALNAME
with the malloc'd full directory name. */
{
char *buf;
int fd = -1;
+ const char *current_what = NULL;
if (dirs == NULL || *dirs == NULL)
{
struct r_search_path_elem *this_dir = *dirs;
size_t buflen = 0;
+ /* If we are debugging the search for libraries print the path
+ now if it hasn't happened now. */
+ if (_dl_debug_libs && current_what != this_dir->what)
+ {
+ current_what = this_dir->what;
+ print_search_path (dirs, current_what, this_dir->where);
+ }
+
if (this_dir->machdirstatus != nonexisting)
{
/* Construct the pathname to try. */
name, namelen)
- buf);
+ /* Print name we try if this is wanted. */
+ if (_dl_debug_libs)
+ _dl_sysdep_message ("\t trying file=", buf, "\n", NULL);
+
fd = __open (buf, O_RDONLY);
if (this_dir->machdirstatus == unknown)
if (fd != -1)
name, namelen)
- buf);
+ /* Print name we try if this is wanted. */
+ if (_dl_debug_libs)
+ _dl_sysdep_message ("\t trying file=", buf, "\n", NULL);
+
fd = __open (buf, O_RDONLY);
if (this_dir->dirstatus == unknown)
if (fd != -1)
size_t namelen = strlen (name) + 1;
+ if (_dl_debug_libs)
+ _dl_sysdep_message ("\tfind library=", name, "; searching\n", NULL);
+
fd = -1;
/* First try the DT_RPATH of the dependent object that caused NAME
+ l->l_info[DT_STRTAB]->d_un.d_ptr
+ l->l_info[DT_RPATH]->d_un.d_val);
l->l_rpath_dirs =
- decompose_rpath ((const char *) ptrval, 0);
+ decompose_rpath ((const char *) ptrval, 0,
+ "RPATH", l->l_name);
}
if (l->l_rpath_dirs != (struct r_search_path_elem **) -1l)
/* Finally, try the default path. */
if (fd == -1)
fd = open_path (name, namelen, preloaded, rtld_search_dirs, &realname);
+
+ /* Add another newline when we a tracing the library loading. */
+ if (_dl_debug_libs)
+ _dl_sysdep_message ("\n", NULL);
}
else
{
/* Name of the architecture. */
const char *_dl_platform;
size_t _dl_platformlen;
+int _dl_debug_libs;
/* If nonzero print warnings about problematic situations. */
int _dl_verbose;
END {
for (i = 0; i < count; ++i) {
printf ("static struct r_search_path_elem rtld_search_dir%d =\n", i+1);
- printf (" { \"%s/\", %d, unknown, 0, nonexisting, ",
+ printf (" { \"%s/\", %d, unknown, 0, nonexisting, NULL, NULL, ",
dir[i], length (dir[i]) + 1);
if (i== 0)
printf ("NULL };\n");
size_t machdirnamelen;
enum r_dir_status machdirstatus;
+ /* Strings saying where the definition came from. */
+ const char *what;
+ const char *where;
+
/* This link is only used in the `all_dirs' member of `r_search_path'. */
struct r_search_path_elem *next;
};
/* Map of shared object to be profiled. */
extern struct link_map *_dl_profile_map;
+/* If nonzero the appropriate debug information if printed. */
+extern int _dl_debug_libs;
+
/* OS-dependent function to open the zero-fill device. */
extern int _dl_sysdep_open_zero_fill (void); /* dl-sysdep.c */
/* Show the members of the auxiliary array passed up from the kernel. */
extern void _dl_show_auxv (void);
+/* Return all environment variables starting with `LD_', one after the
+ other. */
+extern char *_dl_next_ld_env_entry (char ***position);
+
__END_DECLS
#endif /* link.h */
const char *_dl_profile;
const char *_dl_profile_output;
struct link_map *_dl_profile_map;
+int _dl_debug_libs;
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
objname, ": ", errstring, "\n", NULL);
}
\f
+/* Process the string given as the parameter which explains which debugging
+ options are enabled. */
+static void
+process_dl_debug (char *dl_debug)
+{
+ do
+ {
+#define issep(Ch) ((Ch) == ' ' || (Ch) == ',')
+ /* Skip separating white spaces and commas. */
+ while (issep (*dl_debug))
+ ++dl_debug;
+ if (*dl_debug != '\0')
+ {
+ if (strncmp (dl_debug, "libs", 4) == 0
+ && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+ {
+ _dl_debug_libs = 1;
+ dl_debug += 4;
+ }
+ else if (strncmp (dl_debug, "help", 4) == 0
+ && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+ {
+ _dl_sysdep_message ("\
+Valid options for the DL_DEBUG environment variable are:\n\
+\n\
+ help display this help message and exit
+ libs display library search paths\n", NULL);
+ _exit (0);
+ }
+ else
+ /* Skip everything until next separator. */
+ do
+ ++dl_debug;
+ while (*dl_debug != '\0' && !issep (*dl_debug));
+ }
+ }
+ while (*dl_debug != '\0');
+}
+\f
/* Process all environments variables the dynamic linker must recognize.
Since all of them start with `LD_' we are a bit smarter while finding
all the entries. */
if (result < 0)
continue;
+ /* Debugging of the dynamic linker? */
+ result = strncmp (&envline[3], "DEBUG=", 6);
+ if (result == 0)
+ {
+ process_dl_debug (&envline[9]);
+ continue;
+ }
+ if (result < 0)
+ continue;
+
/* Which shared object shall be profiled. */
result = strncmp (&envline[3], "PROFILE=", 8);
if (result == 0)
pread pwrite pread64 pwrite64
aux := init-posix environ
-tests := tstgetopt testfnm runtests
+tests := tstgetopt testfnm runtests wordexp-test
test-srcs := globtest
others := getconf
install-bin := getconf
--- /dev/null
+/* Copyright (C) 1997, 1998 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
+ 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 <wordexp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct test_case_struct
+{
+ int retval;
+ const char *env;
+ const char *words;
+ int flags;
+ int wordc;
+ const char *wordv[10];
+} test_case[] =
+ {
+ { 0, NULL, "one", 0, 1, { "one", } },
+ { 0, NULL, "one two", 0, 2, { "one", "two", } },
+ { 0, NULL, "one two three", 0, 3, { "one", "two", "three", } },
+ { 0, NULL, "~root", 0, 1, { "/root", } },
+ { 0, "foo", "${var}", 0, 1, { "foo", } },
+ { 0, "foo", "$var", 0, 1, { "foo", } },
+ { 0, NULL, "\"quoted\"", 0, 1, { "quoted", } },
+ { -1, NULL, NULL, 0, 0, { NULL, } },
+ };
+
+int
+main (int argc, char * argv[])
+{
+ wordexp_t we;
+ int test;
+ int fail = 0;
+ int retval;
+ int i;
+
+ setenv ("IFS", " \t\n", 1);
+ for (test = 0; test_case[test].retval != -1; test++)
+ {
+ int bzzzt = 0;
+
+ if (test_case[test].env)
+ setenv ("var", test_case[test].env, 1);
+ else
+ unsetenv ("var");
+
+ printf ("Test %d: ", test);
+ retval = wordexp (test_case[test].words, &we, test_case[test].flags);
+
+ if (retval != test_case[test].retval ||
+ we.we_wordc != test_case[test].wordc)
+ bzzzt = 1;
+ else
+ for (i = 0; i < we.we_wordc; i++)
+ if (strcmp (test_case[test].wordv[i], we.we_wordv[i]) != 0)
+ {
+ bzzzt = 1;
+ break;
+ }
+
+ if (bzzzt)
+ {
+ ++fail;
+ printf ("FAILED\n");
+ printf ("Test words: <%s>, need retval %d, wordc %d\n",
+ test_case[test].words, test_case[test].retval,
+ test_case[test].wordc);
+ printf ("Got retval %d, wordc %d: ", retval, we.we_wordc);
+ for (i = 0; i < we.we_wordc; i++)
+ printf ("<%s> ", we.we_wordv[i]);
+ printf ("\n");
+ }
+ else
+ printf ("OK\n");
+
+ wordfree (&we);
+ }
+
+ return fail;
+}
unsigned int i;
const char *best;
+ /* Print a message if the loading of libs is traced. */
+ if (_dl_debug_libs)
+ _dl_sysdep_message ("\t search cache=", LD_SO_CACHE, "\n", NULL);
+
if (cache == NULL)
{
/* Read the contents of the file. */
break;
}
}
+
+ /* Print our result if wanted. */
+ if (_dl_debug_libs && best != NULL)
+ _dl_sysdep_message ("\t trying file=", best, "\n", NULL);
+
return best;
}