We've root caused this bug being related to statically linked binaries (usually
ldconfig) which don't let fakeroot intercept their syscalls.
When ldconfig is run and modifies /etc/ld.so.cache, it creates a new file and
replaces it. However, the old ld.so.cache never gets purged from the fakeroot
database.
If ldconfig modifies symlinks, this can also happen.
A trivial way to get around this is by running a fake ldconfig that adds a
hardlink to ld.so.cache and then
unlinks it, so ldconfig doesn't interfere (ldconfig rarely actually modifies
symlinks on a debian system, since
the packages have the right symlinks)
Some statically linked binaries still exist, so that doesn't totally fix it.
Also, things like fakechroot
clear LD_PRELOAD occasionally in their build process.
A way around this is to detect when the file type on disk changed out from
under us (shouldn't be possible if we're
intercepting the calls) and correct the database, outputting a message from
faked to stderr noting this (as it's
highly irregular).
The first patch (faked-link.diff) fixes it in all cases except when the *new*
inode type is a regular file.
The second fixes it for more cases, wherever this sort of scheme is possible
(i.e. everywhere but inodes that are
regular files in our database but device nodes on disk).
Joe Malicki
Index: faked.c
===================================================================
--- faked.c (revision 86350)
+++ faked.c (working copy)
@@ -633,7 +633,28 @@
i = data_find(&buf->st, buf->remote);
if (i != data_end()) {
st = data_node_get(i);
- st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
+ /* Statically linked binaries can remove inodes without us knowing.
+ ldconfig is a prime offender. Also, some packages run tests without
+ LD_PRELOAD.
+
+ While those cases can be fixed in other ways, we shouldn't continue to
+ cache stale file information.
+
+ mknod() creates a regular file, everything else should have the same
+ file type on disk and in our database. Therefore, we check to see if
+ it's a regular file before blindly applying the new file type.
+ */
+
+ if ((buf->st.mode&S_IFMT) != (st->mode&S_IFMT) &&
+ ((buf->st.mode&S_IFMT) != S_IFREG || (st->mode&(S_ISBLK|S_ISCHR))))
+
+ fprintf(stderr,"FAKEROOT: chmod mode=%lo incompatible with "
+ "existing mode=%lo\n", buf->st.mode, st->mode);
+ st->mode = buf->st.mode;
+ }
+ else{
+ st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
+ }
}
else{
st=&buf->st;
Index: test/Makefile.in
===================================================================
--- test/Makefile.in (revision 86350)
+++ test/Makefile.in (working copy)
@@ -156,7 +156,7 @@
target_vendor = @target_vendor@
AUTOMAKE_OPTIONS = foreign
TESTS = t.echoarg t.mknod t.tar t.truereturn t.falsereturn t.option \
- t.touchinstall
+ t.touchinstall t.no_ld_preload
suffix =
TESTS_ENVIRONMENT = libfakeroot=libfakeroot-0.so suffix=$(suffix) posixshell=$(SHELL)
Index: test/t.no_ld_preload
===================================================================
--- test/t.no_ld_preload (revision 0)
+++ test/t.no_ld_preload (revision 86351)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+../scripts/fakeroot${tcp} -f ../faked${tcp} -l ../.libs/${libfakeroot} -- \
+ ${posixshell} -c 'touch justafile; LD_PRELOAD= rm justafile; mkdir justafile; ls -ld justafile' | grep "^d"
Property changes on: test/t.no_ld_preload
___________________________________________________________________
Added: svn:executable
+ *
Index: test/Makefile.am
===================================================================
--- test/Makefile.am (revision 86350)
+++ test/Makefile.am (working copy)
@@ -1,7 +1,7 @@
AUTOMAKE_OPTIONS=foreign
TESTS = t.echoarg t.mknod t.tar t.truereturn t.falsereturn t.option \
- t.touchinstall
+ t.touchinstall t.no_ld_preload
suffix =
TESTS_ENVIRONMENT = libfakeroot=libfakeroot-0.so suffix=$(suffix) posixshell=$(SHELL)
Index: faked.c
===================================================================
--- faked.c (revision 86350)
+++ faked.c (working copy)
@@ -633,7 +633,27 @@
i = data_find(&buf->st, buf->remote);
if (i != data_end()) {
st = data_node_get(i);
- st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
+ /* Statically linked binaries can remove inodes without us knowing.
+ ldconfig is a prime offender. Also, some packages run tests without
+ LD_PRELOAD.
+
+ While those cases can be fixed in other ways, we shouldn't continue to
+ cache stale file information.
+
+ mknod() creates a regular file, everything else should have the same
+ file type on disk and in our database. Therefore, we check to see if
+ it's a regular file before blindly applying the new file type.
+ */
+
+ if ((buf->st.mode&S_IFMT) != S_IFREG &&
+ (buf->st.mode&S_IFMT) != (st->mode&S_IFMT)) {
+ fprintf(stderr,"FAKEROOT: chmod mode=%lo incompatible with "
+ "existing mode=%lo\n", buf->st.mode, st->mode);
+ st->mode = buf->st.mode;
+ }
+ else{
+ st->mode = (buf->st.mode&~S_IFMT) | (st->mode&S_IFMT);
+ }
}
else{
st=&buf->st;
Index: test/Makefile.in
===================================================================
--- test/Makefile.in (revision 86350)
+++ test/Makefile.in (working copy)
@@ -156,7 +156,7 @@
target_vendor = @target_vendor@
AUTOMAKE_OPTIONS = foreign
TESTS = t.echoarg t.mknod t.tar t.truereturn t.falsereturn t.option \
- t.touchinstall
+ t.touchinstall t.no_ld_preload
suffix =
TESTS_ENVIRONMENT = libfakeroot=libfakeroot-0.so suffix=$(suffix) posixshell=$(SHELL)
Index: test/t.no_ld_preload
===================================================================
--- test/t.no_ld_preload (revision 0)
+++ test/t.no_ld_preload (revision 86351)
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+../scripts/fakeroot${tcp} -f ../faked${tcp} -l ../.libs/${libfakeroot} -- \
+ ${posixshell} -c 'touch justafile; LD_PRELOAD= rm justafile; mkdir justafile; ls -ld justafile' | grep "^d"
Property changes on: test/t.no_ld_preload
___________________________________________________________________
Added: svn:executable
+ *
Index: test/Makefile.am
===================================================================
--- test/Makefile.am (revision 86350)
+++ test/Makefile.am (working copy)
@@ -1,7 +1,7 @@
AUTOMAKE_OPTIONS=foreign
TESTS = t.echoarg t.mknod t.tar t.truereturn t.falsereturn t.option \
- t.touchinstall
+ t.touchinstall t.no_ld_preload
suffix =
TESTS_ENVIRONMENT = libfakeroot=libfakeroot-0.so suffix=$(suffix) posixshell=$(SHELL)