Version 1.4. Now uses FAKECHROOT_CMD_SUBST to remove most %post warnings.
authorRichard Jones <rjones@redhat.com>
Mon, 30 Mar 2009 18:04:34 +0000 (19:04 +0100)
committerRichard Jones <rjones@redhat.com>
Mon, 30 Mar 2009 18:04:34 +0000 (19:04 +0100)
configure.ac
fakechroot-2.9-cmdsubst.patch [new file with mode: 0644]
febootstrap.pod
febootstrap.sh
febootstrap.spec.in

index d7d3d3e..f7aa1fd 100644 (file)
@@ -17,7 +17,7 @@ dnl Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 dnl
 dnl Written by Richard W.M. Jones <rjones@redhat.com>
 
-AC_INIT(febootstrap,1.3)
+AC_INIT(febootstrap,1.4)
 AM_INIT_AUTOMAKE
 
 AC_CHECK_PROG(PERLDOC,[perldoc],[perldoc],[no])
diff --git a/fakechroot-2.9-cmdsubst.patch b/fakechroot-2.9-cmdsubst.patch
new file mode 100644 (file)
index 0000000..0d40cd7
--- /dev/null
@@ -0,0 +1,262 @@
+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
index b2d7470..de10a58 100644 (file)
@@ -148,22 +148,10 @@ C<--foreign> installs - see previous point).
 
 =head1 OTHER RESTRICTIONS AND BUGS
 
-Some C<%post> scripts do not run correctly.  The most common case is
-C</sbin/ldconfig>.  Since this binary is statically linked, fakeroot
-and fakechroot's LD_PRELOAD hack does not work, so effectively
-ldconfig tries to update the system cache.  You will see the following
-error:
-
- /sbin/ldconfig: Can't create temporary cache file /etc/ld.so.cache~: Permission denied
-
-This error is mostly harmless.  Just run C</sbin/ldconfig> the first
-time you boot into the newly created Fedora system.
-
-Another error you will see is with C</usr/sbin/glibc_post_upgrade>
-which is caused for the same reason - this binary is statically
-linked.  We have examined what this binary does, and it is not really
-necessary for installs.  If it makes you happier, you can run it the
-first time you boot the new system.
+C</sbin/ldconfig> and C</usr/sbin/glibc_post_upgrade> are not run
+during C<%post> scriptlets (because they are statically linked, and
+fakechroot cannot run statically linked programs).  If you wish, you
+can run them the first time you boot into the new machine.
 
 febootstrap recreates the repository anew each time, and this causes
 yum to download all the RPMs every time.  This is very wasteful, and
index 5900499..b08e3c0 100755 (executable)
@@ -124,6 +124,11 @@ mkdir -p "$target"/var/cache/yum/febootstrap/packages
 # error: unpacking of archive failed on file /proc: cpio: utime
 export FAKECHROOT_EXCLUDE_PATH=/proc
 
+# Substitute some statically-linked commands.  This is only supported
+# in fakechroot > 2.9.  For previous versions of fakechroot it is
+# ignored.
+export FAKECHROOT_CMD_SUBST=/sbin/ldconfig=/bin/true:/usr/sbin/glibc_post_upgrade.i686=/bin/true:/usr/sbin/glibc_post_upgrade.x86_64=/bin/true
+
 # Make the device nodes inside the fake chroot.
 # (Copied from mock/backend.py)  Why isn't there a base package which
 # creates these?
index a13f148..05292f6 100644 (file)
@@ -14,7 +14,7 @@ BuildArch:   noarch
 BuildRequires: /usr/bin/pod2man
 
 Requires:    fakeroot >= 1.11
-Requires:    fakechroot >= 2.8-15.fc10.rwmj4
+Requires:    fakechroot >= 2.9-1.fc11.rwmj3
 Requires:    yum >= 3.2
 Requires:    MAKEDEV
 Requires:    util-linux-ng