summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.cross8
-rw-r--r--src/Makefile.am5
-rw-r--r--src/cache.c18
-rw-r--r--src/doit.c12
-rw-r--r--src/dso.c20
-rw-r--r--src/execstack.c6
-rw-r--r--src/gather.c12
-rw-r--r--src/get.c2
-rw-r--r--src/main.c26
-rw-r--r--src/prelink.h17
-rw-r--r--src/undoall.c10
-rw-r--r--src/verify.c6
-rw-r--r--src/wrap-file.c536
13 files changed, 630 insertions, 48 deletions
diff --git a/ChangeLog.cross b/ChangeLog.cross
index 9cd2dcc..b9b2d51 100644
--- a/ChangeLog.cross
+++ b/ChangeLog.cross
@@ -1,3 +1,11 @@
+2006-08-08 Montavista Software, Inc.
+
+ * Makefile.am: Add function wrapper support for sysroots
+ * main.c: add --root option
+ * cache.c, doit.c, dso.c, execstack.c, gather.c, get.c,
+ prelink.h, undoall.c, verify.c: Add functional wrappers for sysroot
+ * wrap-file.c: add function wrapper definitions
+
2006-07-28 Alexandre Oliva <aoliva@redhat.com>
* src/cache.c: Avoid SEGFAULT when sorting cache entries (#197451)
diff --git a/src/Makefile.am b/src/Makefile.am
index 6cfe1e1..e5f3b8f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,11 +14,12 @@ arch_SOURCES = arch-i386.c arch-alpha.c arch-ppc.c arch-ppc64.c \
arch-sparc.c arch-sparc64.c arch-x86_64.c \
arch-s390.c arch-s390x.c arch-arm.c arch-sh.c arch-ia64.c
common_SOURCES = checksum.c data.c dso.c dwarf2.c dwarf2.h fptr.c fptr.h \
- hashtab.c hashtab.h mdebug.c prelink.h stabs.c crc32.c
+ hashtab.c hashtab.h mdebug.c prelink.h stabs.c crc32.c \
+ wrap-file.c canonicalize.c
prelink_SOURCES = cache.c conflict.c cxx.c doit.c exec.c execle_open.c get.c \
gather.c layout.c main.c prelink.c \
prelinktab.h reloc.c reloc.h space.c undo.c undoall.c \
- verify.c canonicalize.c md5.c md5.h sha.c sha.h \
+ verify.c md5.c md5.h sha.c sha.h \
$(common_SOURCES) $(arch_SOURCES)
prelink_LDADD = @LIBGELF@
prelink_LDFLAGS = -all-static
diff --git a/src/cache.c b/src/cache.c
index b677e22..2a72267 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -112,8 +112,8 @@ prelink_find_entry (const char *filename, const struct stat64 *stp,
if (! stp)
{
- canon_filename = prelink_canonicalize (filename, &st);
- if (canon_filename == NULL && stat64 (filename, &st) < 0)
+ canon_filename = wrap_prelink_canonicalize (filename, &st);
+ if (canon_filename == NULL && wrap_stat64 (filename, &st) < 0)
{
error (0, errno, "Could not stat %s", filename);
if (insert)
@@ -142,7 +142,7 @@ prelink_find_entry (const char *filename, const struct stat64 *stp,
{
ent = (struct prelink_entry *) *devino_slot;
if (canon_filename == NULL)
- canon_filename = prelink_canonicalize (filename, NULL);
+ canon_filename = wrap_prelink_canonicalize (filename, NULL);
if (canon_filename == NULL)
{
error (0, 0, "Could not canonicalize filename %s", filename);
@@ -189,7 +189,7 @@ prelink_find_entry (const char *filename, const struct stat64 *stp,
if (canon_filename != NULL)
ent->canon_filename = canon_filename;
else
- ent->canon_filename = prelink_canonicalize (filename, NULL);
+ ent->canon_filename = wrap_prelink_canonicalize (filename, NULL);
if (ent->canon_filename == NULL)
{
error (0, 0, "Could not canonicalize filename %s", filename);
@@ -248,7 +248,7 @@ prelink_load_entry (const char *filename)
if (*filename_slot != NULL)
return (struct prelink_entry *) *filename_slot;
- canon_filename = prelink_canonicalize (filename, &st);
+ canon_filename = wrap_prelink_canonicalize (filename, &st);
if (canon_filename == NULL)
goto error_out2;
if (strcmp (canon_filename, filename) != 0)
@@ -364,7 +364,7 @@ prelink_load_cache (void)
size_t cache_size;
uint32_t string_start, *dep;
- fd = open (prelink_cache, O_RDONLY);
+ fd = wrap_open (prelink_cache, O_RDONLY);
if (fd < 0)
return 0; /* The cache does not exist yet. */
@@ -672,7 +672,7 @@ prelink_save_cache (int do_warn)
char prelink_cache_tmp [prelink_cache_len + sizeof (".XXXXXX")];
memcpy (mempcpy (prelink_cache_tmp, prelink_cache, prelink_cache_len),
".XXXXXX", sizeof (".XXXXXX"));
- fd = mkstemp (prelink_cache_tmp);
+ fd = wrap_mkstemp (prelink_cache_tmp);
if (fd < 0)
{
error (0, errno, "Could not write prelink cache");
@@ -683,10 +683,10 @@ prelink_save_cache (int do_warn)
|| write (fd, data, len) != len
|| fchmod (fd, 0644)
|| close (fd)
- || rename (prelink_cache_tmp, prelink_cache))
+ || wrap_rename (prelink_cache_tmp, prelink_cache))
{
error (0, errno, "Could not write prelink cache");
- unlink (prelink_cache_tmp);
+ wrap_unlink (prelink_cache_tmp);
return 1;
}
return 0;
diff --git a/src/doit.c b/src/doit.c
index 31c32fd..2208ece 100644
--- a/src/doit.c
+++ b/src/doit.c
@@ -161,7 +161,7 @@ prelink_ent (struct prelink_entry *ent)
{
size_t len;
- if (lstat64 (hardlink->canon_filename, &st) < 0)
+ if (wrap_lstat64 (hardlink->canon_filename, &st) < 0)
{
error (0, 0, "Could not stat %s (former hardlink to %s)",
hardlink->canon_filename, ent->canon_filename);
@@ -204,19 +204,19 @@ prelink_ent (struct prelink_entry *ent)
memcpy (mempcpy (move, hardlink->canon_filename, len), ".#prelink#",
sizeof (".#prelink#"));
- if (rename (hardlink->canon_filename, move) < 0)
+ if (wrap_rename (hardlink->canon_filename, move) < 0)
{
error (0, errno, "Could not hardlink %s to %s",
hardlink->canon_filename, ent->canon_filename);
continue;
}
- if (link (ent->canon_filename, hardlink->canon_filename) < 0)
+ if (wrap_link (ent->canon_filename, hardlink->canon_filename) < 0)
{
error (0, errno, "Could not hardlink %s to %s",
hardlink->canon_filename, ent->canon_filename);
- if (rename (move, hardlink->canon_filename) < 0)
+ if (wrap_rename (move, hardlink->canon_filename) < 0)
{
error (0, errno, "Could not rename %s back to %s",
move, hardlink->canon_filename);
@@ -224,7 +224,7 @@ prelink_ent (struct prelink_entry *ent)
continue;
}
- if (unlink (move) < 0)
+ if (wrap_unlink (move) < 0)
{
error (0, errno, "Could not unlink %s", move);
continue;
@@ -232,7 +232,7 @@ prelink_ent (struct prelink_entry *ent)
}
free (move);
- if (! dry_run && stat64 (ent->canon_filename, &st) >= 0)
+ if (! dry_run && wrap_stat64 (ent->canon_filename, &st) >= 0)
{
ent->dev = st.st_dev;
ent->ino = st.st_ino;
diff --git a/src/dso.c b/src/dso.c
index 1295e4e..b55d027 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -220,7 +220,7 @@ open_dso (const char *name)
{
int fd;
- fd = open (name, O_RDONLY);
+ fd = wrap_open (name, O_RDONLY);
if (fd == -1)
{
error (0, errno, "cannot open \"%s\"", name);
@@ -756,15 +756,15 @@ reopen_dso (DSO *dso, struct section_move *move, const char *temp_base)
temp_base = dso->filename;
sprintf (filename, "%s.#prelink#.XXXXXX", temp_base);
- fd = mkstemp (filename);
+ fd = wrap_mkstemp (filename);
if (fd == -1)
{
strcpy (filename, "/tmp/#prelink#.XXXXXX");
- fd = mkstemp (filename);
+ fd = wrap_mkstemp (filename);
if (fd == -1)
{
strcpy (filename, "/dev/shm/#prelink#.XXXXXX");
- fd = mkstemp (filename);
+ fd = wrap_mkstemp (filename);
}
if (fd == -1)
{
@@ -1005,7 +1005,7 @@ error_out:
elf_end (elf);
if (fd != -1)
{
- unlink (filename);
+ wrap_unlink (filename);
close (fd);
}
return 1;
@@ -1632,7 +1632,7 @@ close_dso (DSO *dso)
int rdwr = dso_is_rdwr (dso);
if (rdwr && dso->temp_filename != NULL)
- unlink (dso->temp_filename);
+ wrap_unlink (dso->temp_filename);
close_dso_1 (dso);
return 0;
}
@@ -1750,17 +1750,17 @@ update_dso (DSO *dso, const char *orig_name)
close_dso_1 (dso);
u.actime = time (NULL);
u.modtime = st.st_mtime;
- utime (name2, &u);
+ wrap_utime (name2, &u);
if (set_security_context (dso, name2, orig_name ? orig_name : name1))
{
- unlink (name2);
+ wrap_unlink (name2);
return 1;
}
- if (rename (name2, name1))
+ if (wrap_rename (name2, name1))
{
- unlink (name2);
+ wrap_unlink (name2);
error (0, errno, "Could not rename temporary to %s", name1);
return 1;
}
diff --git a/src/execstack.c b/src/execstack.c
index 1e50aad..9f1a4f2 100644
--- a/src/execstack.c
+++ b/src/execstack.c
@@ -107,7 +107,7 @@ execstack_make_rdwr (DSO *dso, int flag)
header we've created. */
sprintf (filename, "%s.#execstack#.XXXXXX", dso->filename);
- fd = mkstemp (filename);
+ fd = wrap_mkstemp (filename);
if (fd == -1)
{
error (0, 0, "%s: Cannot create temporary file",
@@ -183,7 +183,7 @@ execstack_make_rdwr (DSO *dso, int flag)
ndso->filename = p;
p = NULL;
- unlink (filename);
+ wrap_unlink (filename);
close (fd);
fd = -1;
close_dso (dso);
@@ -195,7 +195,7 @@ error_out:
close_dso (ndso);
if (fd != -1)
{
- unlink (filename);
+ wrap_unlink (filename);
close (fd);
}
close_dso (dso);
diff --git a/src/gather.c b/src/gather.c
index a3d0870..a7ebcfd 100644
--- a/src/gather.c
+++ b/src/gather.c
@@ -587,7 +587,7 @@ add_dir_to_dirlist (const char *name, dev_t dev, int flags)
struct prelink_dir *dir;
size_t len;
- canon_name = prelink_canonicalize (name, NULL);
+ canon_name = wrap_prelink_canonicalize (name, NULL);
if (canon_name == NULL)
{
if (! all && implicit)
@@ -693,7 +693,7 @@ gather_func (const char *name, const struct stat64 *st, int type,
if (st->st_size < sizeof (e_ident))
return FTW_CONTINUE;
- fd = open (name, O_RDONLY);
+ fd = wrap_open (name, O_RDONLY);
if (fd == -1)
return FTW_CONTINUE;
@@ -891,7 +891,7 @@ gather_binlib (const char *name, const struct stat64 *st)
return 0;
}
- fd = open (name, O_RDONLY);
+ fd = wrap_open (name, O_RDONLY);
if (fd == -1)
{
error (0, errno, "Could not open %s", name);
@@ -979,7 +979,7 @@ gather_object (const char *name, int deref, int onefs)
{
struct stat64 st;
- if (stat64 (name, &st) < 0)
+ if (wrap_stat64 (name, &st) < 0)
{
if (implicit)
return 0;
@@ -1002,7 +1002,7 @@ gather_object (const char *name, int deref, int onefs)
if (!all && implicit && ! deref)
return 0;
++implicit;
- ret = nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL);
+ ret = wrap_nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL);
--implicit;
#ifndef HAVE_FTW_ACTIONRETVAL
free (blacklist_dir);
@@ -1226,7 +1226,7 @@ add_to_blacklist (const char *name, int deref, int onefs)
return 0;
}
- canon_name = prelink_canonicalize (name, NULL);
+ canon_name = wrap_prelink_canonicalize (name, NULL);
if (canon_name == NULL)
{
if (implicit)
diff --git a/src/get.c b/src/get.c
index 9912a92..2da6fc4 100644
--- a/src/get.c
+++ b/src/get.c
@@ -144,7 +144,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
{
struct stat64 st;
- if (stat64 (filename, &st) < 0)
+ if (wrap_stat64 (filename, &st) < 0)
{
error (0, errno, "%s: Could not stat %s",
info->ent->filename, filename);
diff --git a/src/main.c b/src/main.c
index 9c8b082..02d18cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -77,6 +77,7 @@ static char argp_doc[] = "prelink -- program to relocate and prelink ELF shared
#define OPT_MD5 0x89
#define OPT_SHA 0x8a
#define OPT_COMPUTE_CHECKSUM 0x8b
+#define OPT_SYSROOT 0x8c
static struct argp_option options[] = {
{"all", 'a', 0, 0, "Prelink all binaries" },
@@ -94,6 +95,7 @@ static struct argp_option options[] = {
{"quick", 'q', 0, 0, "Quick scan" },
{"random", 'R', 0, 0, "Choose random base for libraries" },
{"reloc-only", 'r', "BASE_ADDRESS", 0, "Relocate library to given address, don't prelink" },
+ {"root", OPT_SYSROOT, "ROOT_PATH", 0, "Prefix all paths with ROOT_PATH" },
{"undo", 'u', 0, 0, "Undo prelink" },
{"verbose", 'v', 0, 0, "Produce verbose output" },
{"verify", 'y', 0, 0, "Verify file consistency by undoing and redoing prelink and printing original to standard output" },
@@ -222,6 +224,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
case OPT_COMPUTE_CHECKSUM:
compute_checksum = 1;
break;
+ case OPT_SYSROOT:
+ sysroot = arg;
+ break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -237,9 +242,7 @@ main (int argc, char *argv[])
setlocale (LC_ALL, "");
- /* Set the default for exec_shield. */
- if (! access ("/proc/sys/kernel/exec-shield", F_OK))
- exec_shield = 1;
+ exec_shield = 2;
prelink_init_cache ();
@@ -261,6 +264,23 @@ main (int argc, char *argv[])
if ((undo || verify) && quick)
error (EXIT_FAILURE, 0, "--undo and --quick options are incompatible");
+ /* Set the default for exec_shield. */
+ if (exec_shield == 2)
+ {
+ if (sysroot == NULL && ! access ("/proc/sys/kernel/exec-shield", F_OK))
+ exec_shield = 1;
+ else
+ exec_shield = 0;
+ }
+
+ if (sysroot)
+ {
+ sysroot = prelink_canonicalize (sysroot, NULL);
+ if (sysroot == NULL)
+ error (EXIT_FAILURE, 0, "Could not canonicalize --root argument");
+ asprintf ((char **) &prelink_conf, "%s%s", sysroot, prelink_conf);
+ }
+
if (print_cache)
{
prelink_load_cache ();
diff --git a/src/prelink.h b/src/prelink.h
index 17d34fc..72ebf5d 100644
--- a/src/prelink.h
+++ b/src/prelink.h
@@ -21,10 +21,12 @@
#include <elf.h>
#include <libelf.h>
#include <gelfx.h>
+#include <ftw.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
+#include <utime.h>
#ifndef DT_GNU_LIBLIST
#define DT_GNU_LIBLIST 0x6ffffef9
@@ -437,4 +439,19 @@ extern int quick;
extern long long seed;
extern GElf_Addr mmap_reg_start, mmap_reg_end;
+extern const char *sysroot;
+
+char *wrap_prelink_canonicalize (const char *name, struct stat64 *stp);
+int wrap_lstat64 (const char *file, struct stat64 *buf);
+int wrap_stat64 (const char *file, struct stat64 *buf);
+int wrap_open (const char *file, int mode, ...);
+int wrap_access (const char *file, int mode);
+int wrap_rename (const char *old, const char *new);
+int wrap_link (const char *old, const char *new);
+int wrap_nftw64 (const char *dir, __nftw64_func_t func,
+ int descriptors, int flag);
+int wrap_utime (const char *file, struct utimbuf *file_times);
+int wrap_mkstemp (char *filename);
+int wrap_unlink (const char *filename);
+
#endif /* PRELINK_H */
diff --git a/src/undoall.c b/src/undoall.c
index 4ce4670..90e9240 100644
--- a/src/undoall.c
+++ b/src/undoall.c
@@ -88,7 +88,7 @@ undo_one (void **p, void *info)
{
size_t len;
- if (lstat64 (hardlink->canon_filename, &st) < 0)
+ if (wrap_lstat64 (hardlink->canon_filename, &st) < 0)
{
error (0, 0, "Could not stat %s (former hardlink to %s)",
hardlink->canon_filename, ent->canon_filename);
@@ -128,19 +128,19 @@ undo_one (void **p, void *info)
memcpy (mempcpy (move, hardlink->canon_filename, len), ".#prelink#",
sizeof (".#prelink#"));
- if (rename (hardlink->canon_filename, move) < 0)
+ if (wrap_rename (hardlink->canon_filename, move) < 0)
{
error (0, errno, "Could not hardlink %s to %s",
hardlink->canon_filename, ent->canon_filename);
continue;
}
- if (link (ent->canon_filename, hardlink->canon_filename) < 0)
+ if (wrap_link (ent->canon_filename, hardlink->canon_filename) < 0)
{
error (0, errno, "Could not hardlink %s to %s",
hardlink->canon_filename, ent->canon_filename);
- if (rename (move, hardlink->canon_filename) < 0)
+ if (wrap_rename (move, hardlink->canon_filename) < 0)
{
error (0, errno, "Could not rename %s back to %s",
move, hardlink->canon_filename);
@@ -148,7 +148,7 @@ undo_one (void **p, void *info)
continue;
}
- if (unlink (move) < 0)
+ if (wrap_unlink (move) < 0)
{
error (0, errno, "Could not unlink %s", move);
continue;
diff --git a/src/verify.c b/src/verify.c
index 935cbc2..a40c98f 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -193,7 +193,7 @@ prelink_verify (const char *filename)
size_t count;
char *p, *q;
- if (stat64 (filename, &st) < 0)
+ if (wrap_stat64 (filename, &st) < 0)
error (EXIT_FAILURE, errno, "Couldn't stat %s", filename);
dso = open_dso (filename);
@@ -266,7 +266,7 @@ prelink_verify (const char *filename)
break;
}
- fd = open (dso->temp_filename, O_RDONLY);
+ fd = wrap_open (dso->temp_filename, O_RDONLY);
if (fd < 0)
{
error (0, errno, "Could not verify %s", filename);
@@ -430,7 +430,7 @@ failure:
not_prelinked:
if (dso)
close_dso (dso);
- fd = open (filename, O_RDONLY);
+ fd = wrap_open (filename, O_RDONLY);
if (fd < 0)
error (EXIT_FAILURE, errno, "Couldn't open %s", filename);
if (handle_verify (fd, filename))
diff --git a/src/wrap-file.c b/src/wrap-file.c
new file mode 100644
index 0000000..c631458
--- /dev/null
+++ b/src/wrap-file.c
@@ -0,0 +1,536 @@
+/* Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003.
+
+ The chroot_canon function is copied from the GNU C Library,
+ elf/chroot-canon.c, also licensed under the GPL:
+ Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+ [and then further modified.]
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include "prelink.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 20
+#endif
+
+/* Return the canonical absolute name of file NAME as if chroot(CHROOT) was
+ done first. A canonical name does not contain any `.', `..' components
+ nor any repeated path separators ('/') or symlinks. All path components
+ must exist and NAME must be absolute filename. The result is malloc'd.
+ The returned name includes the CHROOT prefix.
+
+ If ALLOW_LAST_LINK, then symlinks in the last component won't be
+ resolved. */
+
+static char *
+chroot_canon_filename (const char * chroot, const char *name, int allow_last_link, struct stat64 *stp)
+{
+ char *rpath, *dest, *extra_buf = NULL;
+ char *rpath_root;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+ int num_links = 0;
+ int stp_initialized = 0;
+ size_t chroot_len = 0;
+
+ if (name == NULL)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (chroot == NULL)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ chroot_len = strlen (chroot);
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf (name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ rpath = malloc (chroot_len + path_max);
+ if (rpath == NULL)
+ return NULL;
+ rpath_limit = rpath + chroot_len + path_max;
+
+ rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1;
+ if (*rpath_root != '/')
+ *++rpath_root = '/';
+ dest = rpath_root + 1;
+
+ for (start = end = name; *start; start = end)
+ {
+ int n;
+
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ stp_initialized = 0;
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+ char *new_rpath;
+
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *) realloc (rpath, new_size);
+ if (new_rpath == NULL)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = mempcpy (dest, start, end - start);
+ *dest = '\0';
+
+ if (lstat64 (rpath, stp) < 0)
+ goto error;
+
+ stp_initialized = 1;
+
+ if (allow_last_link && *end == '\0')
+ goto done;
+
+ if (S_ISLNK (stp->st_mode))
+ {
+ char *buf = alloca (path_max);
+ size_t len;
+
+ if (++num_links > MAXSYMLINKS)
+ {
+ errno = ELOOP;
+ goto error;
+ }
+
+ n = readlink (rpath, buf, path_max);
+ if (n < 0)
+ goto error;
+ buf[n] = '\0';
+
+ if (!extra_buf)
+ extra_buf = alloca (path_max);
+
+ len = strlen (end);
+ if ((long int) (n + len) >= path_max)
+ {
+ errno = ENAMETOOLONG;
+ goto error;
+ }
+
+ /* Careful here, end may be a pointer into extra_buf... */
+ memmove (&extra_buf[n], end, len + 1);
+ name = end = memcpy (extra_buf, buf, n);
+
+ if (buf[0] == '/')
+ dest = rpath_root + 1; /* It's an absolute symlink */
+ else
+ /* Back up to previous component, ignore if at root already: */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ }
+ else if (!S_ISDIR (stp->st_mode) && *end != '\0')
+ {
+ errno = ENOTDIR;
+ goto error;
+ }
+ }
+ }
+done:
+ if (dest > rpath_root + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ if (!stp_initialized && lstat64 (rpath, stp) < 0)
+ goto error;
+
+ if (dest + 1 - rpath <= (rpath_limit - rpath) / 2)
+ {
+ char *new_rpath = realloc (rpath, dest + 1 - rpath);
+
+ if (new_rpath != NULL)
+ return new_rpath;
+ }
+ return rpath;
+
+error:
+ free (rpath);
+ return NULL;
+}
+
+
+const char *sysroot;
+
+static char *
+sysroot_file_name (const char *name, int allow_last_link, struct stat64 *stp)
+{
+ char *ret;
+ struct stat64 st;
+
+ if (sysroot == NULL || name == NULL)
+ return (char *) name;
+
+ if (name[0] != '/')
+ {
+ char *tmpname = malloc (strlen (name) + 2);
+ strcpy (tmpname, "/");
+ strcat (tmpname, name);
+ ret = chroot_canon_filename (sysroot, tmpname, allow_last_link, stp ? stp : &st);
+ free (tmpname);
+ }
+ else
+ ret = chroot_canon_filename (sysroot, name, allow_last_link, stp ? stp : &st);
+
+ if (ret == NULL)
+ {
+ char *ret_root;
+
+ ret = malloc(strlen(sysroot) + strlen(name) + 1);
+ ret_root = mempcpy(ret, sysroot, strlen(sysroot));
+ ret_root = mempcpy(ret_root, name, strlen(name));
+ *ret_root='\0';
+ }
+ return ret;
+}
+
+static char *
+unsysroot_file_name (const char *name)
+{
+ if (name == NULL)
+ return (char *)name;
+
+ if (sysroot)
+ {
+ int sysroot_len = strlen (sysroot);
+ if (strncmp (name, sysroot, sysroot_len) == 0)
+ {
+ if (name[sysroot_len] == '/')
+ return strdup (name + sysroot_len);
+ else if (name[sysroot_len] == 0)
+ return strdup ("/");
+ }
+ }
+ return (char *)name;
+}
+
+char *
+wrap_prelink_canonicalize (const char *name, struct stat64 *stp)
+{
+ if (sysroot)
+ {
+ struct stat64 st;
+ char *tmpname;
+ char *ret;
+
+ /* Use chroot_canon_filename because we want a NULL return if it doesn't exist! */
+ tmpname = chroot_canon_filename (sysroot, name, 0, stp ? stp : &st);
+
+ if (tmpname == NULL)
+ return NULL;
+
+ ret = unsysroot_file_name (tmpname);
+
+ if (ret == tmpname)
+ ret = strdup (ret);
+
+ if (tmpname != name)
+ free (tmpname);
+
+ return ret;
+ }
+ else
+ return prelink_canonicalize(name, stp);
+}
+
+int
+wrap_lstat64 (const char *file, struct stat64 *buf)
+{
+ char *tmpname = sysroot_file_name (file, 1, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = lstat64 (tmpname, buf);
+
+ if (tmpname != file)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_stat64 (const char *file, struct stat64 *buf)
+{
+ char* file_copy;
+ char *tmpname;
+ int ret;
+ int len;
+
+ tmpname = sysroot_file_name (file, 0, NULL);
+
+ if (tmpname == NULL)
+ return -1;
+
+ file_copy = strdup (tmpname);
+
+ if (tmpname != file)
+ free (tmpname);
+
+ if (file_copy == NULL)
+ return -1;
+
+ len = strlen (file_copy);
+ if (file_copy[len - 1] == '/')
+ file_copy[len - 1] = '\0';
+
+ ret = stat64 (file_copy, buf);
+
+ free (file_copy);
+
+ return ret;
+}
+
+int
+wrap_rename (const char *old, const char *new)
+{
+ char *tmpold = sysroot_file_name (old, 1, NULL);
+ char *tmpnew;
+ int ret;
+
+ if (tmpold == NULL)
+ return -1;
+
+ tmpnew = sysroot_file_name (new, 1, NULL);
+ if (tmpnew == NULL)
+ return -1;
+
+ ret = rename (tmpold, tmpnew);
+
+ if (tmpold != old)
+ free (tmpold);
+ if (tmpnew != new)
+ free (tmpnew);
+ return ret;
+}
+
+int
+wrap_open (const char *name, int mode, ...)
+{
+ char *tmpname = sysroot_file_name (name, 0, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ if (mode & O_CREAT)
+ {
+ va_list va;
+ int flags;
+ va_start (va, mode);
+ flags = va_arg (va, int);
+ va_end (va);
+ ret = open (tmpname, mode, flags);
+ }
+ else
+ ret = open (tmpname, mode);
+
+ if (tmpname != name)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_access (const char *name, int mode)
+{
+ char *tmpname = sysroot_file_name (name, 0, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = access (tmpname, mode);
+
+ if (tmpname != name)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_link (const char *old, const char *new)
+{
+ char *tmpold = sysroot_file_name (old, 1, NULL);
+ char *tmpnew;
+ int ret;
+
+ if (tmpold == NULL)
+ return -1;
+
+ tmpnew = sysroot_file_name (new, 1, NULL);
+ if (tmpnew == NULL)
+ return -1;
+
+ ret = link (tmpold, tmpnew);
+
+ if (tmpold != old)
+ free (tmpold);
+ if (tmpnew != new)
+ free (tmpnew);
+ return ret;
+}
+
+/* Note that this isn't recursive safe, since nftw64 doesn't
+ pass an opaque object around to use. But that fits our needs
+ for now. */
+
+static __nftw64_func_t nftw64_cur_func;
+
+static int
+wrap_nftw64_func (const char *filename, const struct stat64 *status,
+ int flag, struct FTW *info)
+{
+ char *tmpname = unsysroot_file_name (filename);
+ int ret = nftw64_cur_func (tmpname, status, flag, info);
+
+ if (tmpname != filename)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_nftw64 (const char *dir, __nftw64_func_t func,
+ int descriptors, int flag)
+{
+ char *tmpdir = sysroot_file_name (dir, 1, NULL);
+ int ret;
+
+ if (tmpdir == NULL)
+ return -1;
+
+ nftw64_cur_func = func;
+ ret = nftw64 (tmpdir, wrap_nftw64_func, descriptors, flag);
+
+ if (tmpdir != dir)
+ free (tmpdir);
+ return ret;
+}
+
+int
+wrap_utime (const char *file, struct utimbuf *file_times)
+{
+ char *tmpname = sysroot_file_name (file, 0, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = utime (tmpname, file_times);
+
+ if (tmpname != file)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_mkstemp (char *filename)
+{
+ char *tmpname = sysroot_file_name (filename, 1, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = mkstemp (tmpname);
+
+ if (tmpname != filename)
+ {
+ strcpy (filename, tmpname + strlen (sysroot));
+ free (tmpname);
+ }
+ return ret;
+}
+
+int
+wrap_unlink (const char *filename)
+{
+ char *tmpname = sysroot_file_name (filename, 1, NULL);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = unlink (tmpname);
+
+ if (tmpname != filename)
+ free (tmpname);
+ return ret;
+}