--- /dev/null
+Index: test/cmd-subst-pwd.sh
+===================================================================
+--- test/cmd-subst-pwd.sh (revision 0)
++++ test/cmd-subst-pwd.sh (revision 0)
+@@ -0,0 +1,3 @@
++#!/bin/sh
++
++echo substituted
+
+Property changes on: test/cmd-subst-pwd.sh
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Index: test/cmd-subst.t
+===================================================================
+--- test/cmd-subst.t (revision 0)
++++ test/cmd-subst.t (revision 0)
+@@ -0,0 +1,37 @@
++#!/bin/sh
++
++. ./tap.sh
++
++plan 5
++
++rm -rf testtree
++
++./testtree.sh testtree
++test "`cat testtree/CHROOT`" = "testtree" || not
++ok "testtree"
++
++t=`./fakechroot.sh testtree /bin/pwd`
++test "$t" = "/" || not
++ok "fakechroot pwd is /"
++
++export FAKECHROOT_CMD_SUBST="/bin/pwd=$(pwd)/cmd-subst-pwd.sh"
++
++t=`./fakechroot.sh testtree /bin/pwd`
++test "$t" = "substituted" || not
++ok "fakechroot substituted pwd (1)"
++
++export FAKECHROOT_CMD_SUBST="/no/file=foo:/bin/pwd=$(pwd)/cmd-subst-pwd.sh"
++
++t=`./fakechroot.sh testtree /bin/pwd`
++test "$t" = "substituted" || not
++ok "fakechroot substituted pwd (2)"
++
++export FAKECHROOT_CMD_SUBST="/no/file=foo:/other/file=bar"
++
++t=`./fakechroot.sh testtree /bin/pwd`
++test "$t" = "/" || not
++ok "fakechroot not substituted pwd is /"
++
++rm -rf testtree
++
++end
+
+Property changes on: test/cmd-subst.t
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Index: test/Makefile.am
+===================================================================
+--- test/Makefile.am (revision 323)
++++ test/Makefile.am (working copy)
+@@ -1,6 +1,6 @@
+ SUBDIRS = src
+
+-TESTS = chroot.t escape-nested-chroot.t pwd.t touch.t
++TESTS = chroot.t cmd-subst.t escape-nested-chroot.t pwd.t touch.t
+
+ suffix =
+
+Index: src/libfakechroot.c
+===================================================================
+--- src/libfakechroot.c (revision 323)
++++ src/libfakechroot.c (working copy)
+@@ -1467,7 +1467,38 @@
+ return execve (path, argv, environ);
+ }
+
++/* Parse the FAKECHROOT_CMD_SUBST environment variable (the first
++ * parameter) and if there is a match with filename, return the
++ * substitution in cmd_subst. Returns non-zero if there was a match.
++ *
++ * FAKECHROOT_CMD_SUBST=cmd=subst:cmd=subst:...
++ */
++static int
++try_cmd_subst (char *env, const char *filename, char *cmd_subst)
++{
++ int len = strlen (filename), len2;
++ char *p;
+
++ if (env == NULL) return 0;
++
++ do {
++ p = strchrnul (env, ':');
++
++ if (strncmp (env, filename, len) == 0 && env[len] == '=') {
++ len2 = p - &env[len+1];
++ if (len2 >= FAKECHROOT_MAXPATH)
++ len2 = FAKECHROOT_MAXPATH - 1;
++ strncpy (cmd_subst, &env[len+1], len2);
++ cmd_subst[len2] = '\0';
++ return 1;
++ }
++
++ env = p;
++ } while (*env++ != '\0');
++
++ return 0;
++}
++
+ /* #include <unistd.h> */
+ int execve (const char *filename, char *const argv [], char *const envp[])
+ {
+@@ -1479,32 +1510,16 @@
+ char *env;
+ char tmp[FAKECHROOT_MAXPATH], newfilename[FAKECHROOT_MAXPATH], argv0[FAKECHROOT_MAXPATH];
+ char *ptr;
+- unsigned int i, j, n, len;
++ unsigned int i, j, n, len, r, newenvppos;
+ size_t sizeenvp;
+ char c;
+ char *fakechroot_path, *fakechroot_ptr, fakechroot_buf[FAKECHROOT_MAXPATH];
+ char *envkey[] = { "FAKECHROOT", "FAKECHROOT_BASE",
+ "FAKECHROOT_VERSION", "FAKECHROOT_EXCLUDE_PATH",
++ "FAKECHROOT_CMD_SUBST",
+ "LD_LIBRARY_PATH", "LD_PRELOAD" };
++ const int nr_envkey = sizeof envkey / sizeof envkey[0];
+
+- strncpy(argv0, filename, FAKECHROOT_MAXPATH);
+-
+- expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf);
+- strcpy(tmp, filename);
+- filename = tmp;
+-
+- if ((file = open(filename, O_RDONLY)) == -1) {
+- errno = ENOENT;
+- return -1;
+- }
+-
+- i = read(file, hashbang, FAKECHROOT_MAXPATH-2);
+- close(file);
+- if (i == -1) {
+- errno = ENOENT;
+- return -1;
+- }
+-
+ if (next_execve == NULL) fakechroot_init();
+
+ /* Scan envp and check its size */
+@@ -1514,39 +1529,69 @@
+ }
+
+ /* Copy envp to newenvp */
+- newenvp = malloc( sizeenvp * sizeof (char *) + sizeof(envkey) );
++ newenvp = malloc( (sizeenvp + 1) * sizeof (char *) );
+ if (newenvp == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+- for (ep = envp, i = 0; *ep != NULL; ++ep) {
+- for (j = 0; j < sizeof (envkey) / sizeof (char *); j++) {
++ for (ep = envp, newenvppos = 0; *ep != NULL; ++ep) {
++ for (j = 0; j < nr_envkey; j++) {
+ len = strlen (envkey[j]);
+ if (strncmp (*ep, envkey[j], len) == 0 && (*ep)[len] == '=')
+ goto skip;
+ }
+- newenvp[i] = *ep;
+- i++;
++ newenvp[newenvppos] = *ep;
++ newenvppos++;
+ skip: ;
+ }
++ newenvp[newenvppos] = NULL;
+
++ strncpy(argv0, filename, FAKECHROOT_MAXPATH);
++
++ r = try_cmd_subst (getenv ("FAKECHROOT_CMD_SUBST"), filename, tmp);
++ if (r) {
++ filename = tmp;
++
++ /* FAKECHROOT_CMD_SUBST escapes the chroot. newenvp here does
++ * not contain LD_PRELOAD and the other special environment
++ * variables.
++ */
++ return next_execve(filename, argv, newenvp);
++ }
++
++ expand_chroot_path(filename, fakechroot_path, fakechroot_ptr, fakechroot_buf);
++ strcpy(tmp, filename);
++ filename = tmp;
++
++ if ((file = open(filename, O_RDONLY)) == -1) {
++ errno = ENOENT;
++ return -1;
++ }
++
++ i = read(file, hashbang, FAKECHROOT_MAXPATH-2);
++ close(file);
++ if (i == -1) {
++ errno = ENOENT;
++ return -1;
++ }
++
+ /* Add our variables to newenvp */
+- newenvp = realloc( newenvp, i * sizeof(char *) + sizeof(envkey) );
++ newenvp = realloc( newenvp, (newenvppos + nr_envkey + 1) * sizeof(char *) );
+ if (newenvp == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+- for (j = 0; j < sizeof(envkey) / sizeof(char *); j++) {
++ for (j = 0; j < nr_envkey; j++) {
+ env = getenv(envkey[j]);
+ if (env != NULL) {
+- newenvp[i] = malloc(strlen(envkey[j]) + strlen(env) + 3);
+- strcpy(newenvp[i], envkey[j]);
+- strcat(newenvp[i], "=");
+- strcat(newenvp[i], env);
+- i++;
++ newenvp[newenvppos] = malloc(strlen(envkey[j]) + strlen(env) + 3);
++ strcpy(newenvp[newenvppos], envkey[j]);
++ strcat(newenvp[newenvppos], "=");
++ strcat(newenvp[newenvppos], env);
++ newenvppos++;
+ }
+ }
+- newenvp[i] = NULL;
++ newenvp[newenvppos] = NULL;
+
+ /* No hashbang in argv */
+ if (hashbang[0] != '#' || hashbang[1] != '!')
+Index: man/fakechroot.pod
+===================================================================
+--- man/fakechroot.pod (revision 323)
++++ man/fakechroot.pod (working copy)
+@@ -139,6 +139,21 @@
+ The list of directories which are excluded from being chrooted. The elements
+ of list are separated with colon.
+
++=item B<FAKECHROOT_CMD_SUBST>
++
++A list of command substitutions. If a program tries to execute one of
++the commands given (path relative to the chroot) then the substitute
++command runs instead (path to substitute command is not chrooted).
++
++For example:
++
++ FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/tmp/ldconfig-wrapper
++
++will substitute C</tmp/ldconfig-wrapper> for C</sbin/ldconfig>.
++
++Give as many substitute commands as you want, separated by C<:>
++(colon) characters.
++
+ =item B<LD_LIBRARY_PATH>, B<LD_PRELOAD>
+
+ Fakechroot is implemented by wrapping system calls. This is accomplished by