Makefile.am | 9 ++- configure.ac | 15 ++--- faked.c | 187 ++++++++++++++++++++++++++++++++------------------- libfakeroot.c | 11 +++- scripts/fakeroot.in | 22 +++--- symver.awk | 26 +++++++ test/compare-tar | 4 +- wrapawk | 6 +- 8 files changed, 181 insertions(+), 99 deletions(-) diff --git a/Makefile.am b/Makefile.am index 66e21e3..945654c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,10 +17,10 @@ faked_LDADD = libcommunicate.la simple_SOURCES=simple.c noinst_PROGRAMS=simple -CLEANFILES= wrapdef.h wrapstruct.h wrapped.h wraptmpf.h +CLEANFILES= wrapdef.h wrapstruct.h wrapped.h wraptmpf.h symver.h DISTCLEANFILES = fakerootconfig.h -EXTRA_DIST=wrapawk wrapfunc.inp \ +EXTRA_DIST=wrapawk wrapfunc.inp symver.awk \ debian/rules debian/changelog debian/control \ message.h \ DEBUG BUGS \ @@ -31,7 +31,10 @@ CLEAN_FILES=fakerootconfig.h wrapped.h wrapdef.h wrapstruct.h wraptmpf.h:wrapawk wrapfunc.inp awk -f $(srcdir)/wrapawk < $(srcdir)/wrapfunc.inp -libfakeroot.lo:libfakeroot.c wrapdef.h wrapstruct.h wraptmpf.h +symver.h: symver.awk + readelf -Ws $(LIBCPATH) |awk -f $(srcdir)/symver.awk > $@ + +libfakeroot.lo:libfakeroot.c wrapdef.h wrapstruct.h wraptmpf.h symver.h fakerootconfig.h: ./config.status CONFIG_FILES= CONFIG_HEADERS= /bin/sh ./config.status diff --git a/configure.ac b/configure.ac index b19e01b..b744a91 100644 --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,13 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT([fakeroot],[FAKEROOT_VERSION],[schizo@debian.org],[fakeroot]) -AC_PREREQ(2.61) -LT_PREREQ(2.1a) +AC_PREREQ(2.59) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_MAINTAINER_MODE AC_CONFIG_HEADERS([config.h]) AC_PROG_MAKE_SET -LT_INIT -LT_LANG(C) +AM_PROG_LIBTOOL +AC_PROG_CC AH_BOTTOM([#if ! HAVE_BUILTIN_EXPECT #define __builtin_expect(x, expected_value) (x) @@ -417,6 +416,7 @@ case $target_cpu:$target_os in esac AC_DEFINE_UNQUOTED([LIBCPATH], "$libcpath", [path to libc shared object]) +AC_SUBST([LIBCPATH], [$libcpath]) AC_SUBST(DLSUFFIX) AC_SUBST(LDLIBPATHVAR) AC_SUBST(LDPRELOADVAR) @@ -424,7 +424,7 @@ AC_SUBST(LDPRELOADABS) AC_SUBST(LDEXTRAVAR) dnl Checks for library functions. -AC_CHECK_FUNCS(strdup strstr getresuid setresuid getresgid setresgid setfsuid setfsgid) +AC_CHECK_FUNCS(strdup strstr getresuid setresuid getresgid setresgid setfsuid setfsgid dlvsym) AC_CHECK_DECLS([setenv, unsetenv]) AC_REPLACE_FUNCS([setenv]) @@ -489,11 +489,6 @@ AH_VERBATIM([WRAP_STAT], ]) dnl kludge end -dnl check for b0rked Solaris (and other shells) and find one that works -_AS_DETECT_REQUIRED([echo $(echo ok) > config.$$ 2>/dev/null - j=`cat config.$$` - test "x$j" = "xok"]) - case "$target_cpu:$target_os" in (alpha*:linux*) AH_TEMPLATE([STUPID_ALPHA_HACK], [stat-struct conversion hackery]) diff --git a/faked.c b/faked.c index aedb884..d8f3d9d 100644 --- a/faked.c +++ b/faked.c @@ -94,8 +94,10 @@ #include #include #include +#include #ifdef HAVE_STDINT_H # include +# include #endif #ifdef HAVE_SYS_SYSMACROS_H # include @@ -114,6 +116,10 @@ # define SOL_TCP 6 /* this should probably be done with getprotoent */ #endif +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif + #define fakestat_equal(a, b) ((a)->dev == (b)->dev && (a)->ino == (b)->ino) #ifndef FAKEROOT_FAKENET @@ -151,25 +157,25 @@ unsigned int highest_funcid = sizeof(func_arr)/sizeof(func_arr[0]); key_t msg_key=0; #else /* FAKEROOT_FAKENET */ static int comm_sd = -1; -static volatile int detached = 0; +static volatile sig_atomic_t detached = 0; #endif /* FAKEROOT_FAKENET */ int debug = 0, unknown_is_real = 0; char *save_file = NULL; +static sigjmp_buf jmpbuf; +static sigset_t mask_busy; void cleanup(int); -#ifdef FAKEROOT_FAKENET static void fail(const char *msg) { if (errno > 0) - fprintf(stderr, "fakeroot daemon: %s (%s)\n", msg, strerror(errno)); + fprintf(stderr, "fakeroot daemon: %s: %m\n", msg); else fprintf(stderr, "fakeroot daemon: %s\n", msg); exit(1); } -#endif struct data_node_s; typedef struct data_node_s { @@ -495,15 +501,17 @@ int save_database(const uint32_t remote) #ifdef FAKEROOT_DB_PATH if (find_path(i->buf.dev, i->buf.ino, roots, path)) - fprintf(f,"mode=%llo,uid=%llu,gid=%llu,nlink=%llu,rdev=%llu %s\n", + fprintf(f,"mode=%" PRIx64 ",uid=%" PRIu64 ",gid=%" PRIu64 ",nlink=%" PRIu64 ",rdev=%" PRIu64 " %s\n", (uint64_t) i->buf.mode,(uint64_t) i->buf.uid,(uint64_t) i->buf.gid, (uint64_t) i->buf.nlink,(uint64_t) i->buf.rdev,path); #else - fprintf(f,"dev=%llx,ino=%llu,mode=%llo,uid=%llu,gid=%llu,nlink=%llu,rdev=%llu\n", + fprintf(f,"dev=%" PRIx64 ",ino=%" PRIu64 ",mode=%" PRIo64 ",uid=%" PRIu64 ",gid=%" PRIu64 ",nlink=%" PRIu64 ",rdev=%" PRIu64 "\n", (uint64_t) i->buf.dev,(uint64_t) i->buf.ino,(uint64_t) i->buf.mode, (uint64_t) i->buf.uid,(uint64_t) i->buf.gid,(uint64_t) i->buf.nlink, (uint64_t) i->buf.rdev); #endif + if (ferror(f)) + fail(save_file); } return fclose(f); @@ -525,13 +533,13 @@ int load_database(const uint32_t remote) while(1){ #ifdef FAKEROOT_DB_PATH - r=scanf("mode=%llo,uid=%llu,gid=%llu,nlink=%llu,rdev=%llu "DB_PATH_SCAN"\n", + r=scanf("mode=%" PRIo64 ",uid=%" PRIu64 ",gid=%" PRIu64 ",nlink=%" PRIu64 ",rdev=%" PRIu64 " "DB_PATH_SCAN"\n", &stmode, &stuid, &stgid, &stnlink, &strdev, &path); if (r != 6) break; if (stat(path, &path_st) < 0) { - fprintf(stderr, "%s: %s\n", path, strerror(errno)); + fprintf(stderr, "%s: %m\n", path); if (errno == ENOENT || errno == EACCES) continue; else @@ -540,7 +548,7 @@ int load_database(const uint32_t remote) stdev = path_st.st_dev; stino = path_st.st_ino; #else - r=scanf("dev=%llx,ino=%llu,mode=%llo,uid=%llu,gid=%llu,nlink=%llu,rdev=%llu\n", + r=scanf("dev=%" PRIx64 ",ino=%" PRIu64 ",mode=%" PRIo64 ",uid=%" PRIu64 ",gid=%" PRIu64 ",nlink=%" PRIu64 ",rdev=%" PRIu64 "\n", &stdev, &stino, &stmode, &stuid, &stgid, &stnlink, &strdev); if (r != 7) break; @@ -567,7 +575,7 @@ int load_database(const uint32_t remote) /* */ /*********************************/ void debug_stat(const struct fakestat *st){ - fprintf(stderr,"dev:ino=(%llx:%lli), mode=0%lo, own=(%li,%li), nlink=%li, rdev=%lli\n", + fprintf(stderr,"dev:ino=(%" PRIx64 ":%" PRIi64 "), mode=0%lo, own=(%li,%li), nlink=%li, rdev=%" PRIi64 "\n", st->dev, st->ino, (long)st->mode, @@ -751,8 +759,13 @@ void process_msg(struct fake_msg *buf){ func_id_t f; f= buf->id; - if (f <= highest_funcid) + if (f <= highest_funcid) { + sigset_t mask_save; + + sigprocmask(SIG_SETMASK, &mask_busy, &mask_save); func_arr[f]((struct fake_msg*)buf); + sigprocmask(SIG_SETMASK, &mask_save, NULL); + } } #ifndef FAKEROOT_FAKENET @@ -882,7 +895,7 @@ void get_msg(const int listen_sd) /* */ /***********/ -void save(int dummy){ +void save(int dummy UNUSED){ int savedb_state; savedb_state = save_database(0); if(!savedb_state) { @@ -895,21 +908,21 @@ void save(int dummy){ #ifdef FAKEROOT_FAKENET static void detach(int g) { - int saved_errno = errno; - - if (debug) - fprintf(stderr, "fakeroot: detaching, signal=%i\n", g); - detached = 1; - errno = saved_errno; + if (debug) { + int saved_errno = errno; + + fprintf(stderr, "fakeroot: detaching, signal=%i\n", g); + errno = saved_errno; + } } #endif /* FAKEROOT_FAKENET */ #ifndef FAKEROOT_FAKENET -# define FAKEROOT_CLEANUPMSG "fakeroot: clearing up message queues and semaphores, signal=%i\n" +# define FAKEROOT_CLEANUPMSG "fakeroot: clearing up message queues and semaphores, param=%i\n" #else /* FAKEROOT_FAKENET */ -# define FAKEROOT_CLEANUPMSG "fakeroot: signal=%i\n" +# define FAKEROOT_CLEANUPMSG "fakeroot: param=%i\n" #endif /* FAKEROOT_FAKENET */ void cleanup(int g) @@ -918,6 +931,8 @@ void cleanup(int g) union semun sem_union; #endif /* ! FAKEROOT_FAKENET */ + sigprocmask(SIG_SETMASK, &mask_busy, NULL); + if(debug) fprintf(stderr, FAKEROOT_CLEANUPMSG, g); @@ -928,9 +943,7 @@ void cleanup(int g) #endif /* ! FAKEROOT_FAKENET */ save(0); - - if(g!=-1) - exit(0); + exit(g); } /*************/ @@ -983,6 +996,16 @@ static int get_fakem(struct fake_msg *buf) } #endif /* FAKEROOT_FAKENET */ +static void abort_handler(int dummy UNUSED){ + const char msg[] = "faked: aborted by unhandled signal\n"; + write(2, msg, sizeof(msg)-1); + _exit(2); +} + +static void cleanup_handler(int dummy UNUSED){ + siglongjmp(jmpbuf, 1); +} + int main(int argc, char **argv){ struct sigaction sa,sa_debug,sa_save; int i; @@ -1052,6 +1075,14 @@ int main(int argc, char **argv){ } } + sigprocmask(SIG_SETMASK, NULL, &mask_busy); + sigaddset(&mask_busy, SIGHUP); + sigaddset(&mask_busy, SIGINT); + sigaddset(&mask_busy, SIGQUIT); + sigaddset(&mask_busy, SIGTERM); + sigaddset(&mask_busy, SIGUSR1); + sigaddset(&mask_busy, SIGUSR2); + init_hash_table(); if(load) @@ -1081,8 +1112,7 @@ int main(int argc, char **argv){ if((msg_get==-1)||(msg_snd==-1)||(sem_id==-1)){ perror("fakeroot, while creating message channels"); fprintf(stderr, "This may be due to a lack of SYSV IPC support.\n"); - cleanup(-1); - exit(1); + cleanup(1); } if(debug) @@ -1125,60 +1155,39 @@ int main(int argc, char **argv){ port = ntohs(addr.sin_port); sa_detach.sa_handler=detach; - sigemptyset(&sa_detach.sa_mask); + sa_detach.sa_mask=mask_busy; sa_detach.sa_flags=0; #endif /* FAKEROOT_FAKENET */ - sa.sa_handler=cleanup; - sigemptyset(&sa.sa_mask); - sa.sa_flags=0; - // sa.sa_restorer=0; - sa_debug.sa_handler=debugdata; - sigemptyset(&sa_debug.sa_mask); + sa_debug.sa_mask=mask_busy; sa_debug.sa_flags=0; - // sa_debug.sa_restorer=0; sa_save.sa_handler=save; - sigemptyset(&sa_save.sa_mask); + sa_save.sa_mask=mask_busy; sa_save.sa_flags=0; - for(i=1; i< NSIG; i++){ - switch (i){ - case SIGKILL: - case SIGTSTP: - case SIGCONT: - break; - case SIGUSR1: - /* this is strictly a debugging feature, unless someone can confirm - that save will always get a consistent database */ - sigaction(i,&sa_save,NULL); - break; - case SIGUSR2: - sigaction(i,&sa_debug,NULL); - break; -#ifdef FAKEROOT_FAKENET - case SIGHUP: - sigaction(i,&sa_detach,NULL); - break; -#endif /* FAKEROOT_FAKENET */ - default: - sigaction(i,&sa,NULL); - break; - } - } - if(!foreground){ - /* literally copied from the linux klogd code, go to background */ - if ((pid=fork()) == 0){ - int fl; - int num_fds = getdtablesize(); - - fflush(stdout); + /* Copied from the linux klogd code, go to background */ + int fl; + + if ((fl = open(_PATH_DEVNULL, O_RDWR)) < 0) + fail(_PATH_DEVNULL); + + if ((pid = fork()) == -1) + fail("fork"); + else if (pid == 0) + { + int num_fds; /* This is the child closing its file descriptors. */ - for (fl= 0; fl <= num_fds; ++fl) + if ((dup2(fl, 0) != 0) || + (dup2(fl, 1) != 1)) + fail("dup2"); + + num_fds = getdtablesize(); + for (fl= 3; fl <= num_fds; ++fl) #ifdef FAKEROOT_FAKENET if (fl != sd) #endif /* FAKEROOT_FAKENET */ @@ -1194,13 +1203,55 @@ int main(int argc, char **argv){ fflush(stdout); } + sa.sa_handler=abort_handler; + sigfillset(&sa.sa_mask); + sa.sa_flags=0; + + for(i=1; i&2 "fakeroot: database file \`$1' does not exist." @@ -70,11 +70,11 @@ while test "X$1" != "X--"; do ;; -s) shift - FAKEDOPTS=$FAKEDOPTS" --save-file $1" - [ -p $1 ] || WAITINTRAP=1 + FAKEDOPTS="$FAKEDOPTS --save-file $1" + [ -p "$1" ] || WAITINTRAP=1 ;; -u|--unknown-is-real) - FAKEDOPTS=$FAKEDOPTS" --unknown-is-real" + FAKEDOPTS="$FAKEDOPTS --unknown-is-real" FAKED_MODE="unknown-is-real" ;; -b|--fd-base) @@ -98,7 +98,7 @@ shift #get rid of the '--' ABSLIB="" if [ -n "$PATHS" ] then - for dir in `echo $PATHS | sed 's/:/ /g'` + for dir in `echo $PATHS | tr : ' '` do if test -r "$dir/$LIB" then @@ -132,17 +132,17 @@ KEY_PID=`eval $FAKED $FAKEDOPTS $PIPEIN` FAKEROOTKEY=`echo $KEY_PID|cut -d: -f1` PID=`echo $KEY_PID|cut -d: -f2` -if [ "$WAITINTRAP" -eq 0 ]; then - trap "kill -s @signal@ $PID" EXIT INT -else - trap 'FAKEROOTKEY=$FAKEROOTKEY LD_LIBRARY_PATH="$PATHS" LD_PRELOAD="$LIB" /bin/ls -l / >/dev/null 2>&1; while kill -s @signal@ $PID 2>/dev/null; do sleep 0.1; done' EXIT INT -fi - if test -z "$FAKEROOTKEY" || test -z "$PID"; then echo >&2 "fakeroot: error while starting the \`faked' daemon." exit 1 fi +if [ "$WAITINTRAP" -eq 0 ]; then + trap "kill -s @signal@ $PID" EXIT INT QUIT TERM +else + trap "kill -s @signal@ $PID; while kill -0 $PID 2>/dev/null; do sleep 0.01; done" EXIT INT QUIT TERM +fi + if test $USEABSLIBPATH -ne 0 ; then LIB=$ABSLIB fi diff --git a/symver.awk b/symver.awk new file mode 100644 index 0000000..5c745ce --- /dev/null +++ b/symver.awk @@ -0,0 +1,26 @@ +#!/bin/awk +BEGIN { + print "/* Automatically generated file. Do not edit. See symver.awk. */"; + print "" +} +$4 == "FUNC" && $6 == "DEFAULT" && $8 ~ /@@/ { + sym=$8; + name=gensub("@@.*", "", 1, sym); + vers=gensub("^[^@]*@@", "", 1, sym); + printf("#define sym_%s_ver \"%s\"\n", name, vers); +} +END { + print "" + print "#define sym_wrap_fstat_ver sym___fxstat_ver"; + print "#define sym_wrap_fstat64_ver sym___fxstat64_ver"; + print "#define sym_wrap_fstatat_ver sym___fxstatat_ver"; + print "#define sym_wrap_fstatat64_ver sym___fxstatat64_ver"; + print "#define sym_wrap_lstat64_ver sym___lxstat64_ver"; + print "#define sym_wrap_lstat_ver sym___lxstat_ver"; + print "#define sym_wrap_mknod_ver sym___xmknod_ver"; + print "#define sym_wrap_mknodat_ver sym___xmknodat_ver"; + print "#define sym_wrap_stat_ver sym___xstat_ver"; + print "#define sym_wrap_stat64_ver sym___xstat64_ver"; + print "#define sym_acl_set_fd_ver NULL"; + print "#define sym_acl_set_file_ver NULL"; +} diff --git a/test/compare-tar b/test/compare-tar index d764705..4f2a069 100755 --- a/test/compare-tar +++ b/test/compare-tar @@ -2,8 +2,8 @@ set -e echo compare-tar: -gzip -dc $1 | tar -tvf - |awk '{print $1, $2, $3, $NF}' |sort > tmp-1 -gzip -dc $2 | tar -tvf - |awk '{print $1, $2, $3, $NF}' |sort > tmp-2 +gzip -dc $1 | tar -tvf - |awk '{print $1, $2, $3, $NF}' |sed 's/sys\|adm/bin/g' |sort > tmp-1 +gzip -dc $2 | tar -tvf - |awk '{print $1, $2, $3, $NF}' |sed 's/sys\|adm/bin/g' |sort > tmp-2 diff tmp-1 tmp-2 > tmp-diff || true diff --git a/wrapawk b/wrapawk index a2fd220..6c65b68 100644 --- a/wrapawk +++ b/wrapawk @@ -38,7 +38,7 @@ BEGIN{ argname=$4; MACRO=$5; if(MACRO){ - print " {(void(*))&NEXT_" MACRO "_NOARG, " name "_QUOTE}," > structfile; + print " {(void(*))&NEXT_" MACRO "_NOARG, " name "_QUOTE, sym_" tolower(name) "_ver}," > structfile; print "extern " ret " (*NEXT_" MACRO "_NOARG)" argtype ";" > headerfile; print ret " (*NEXT_" MACRO "_NOARG)" argtype "=TMP_" MACRO ";"> deffile; @@ -48,7 +48,7 @@ BEGIN{ print "}" > tmpffile; print "" > tmpffile; } else { - print " {(void(*))&next_" name ", \"" name "\"}," > structfile; + print " {(void(*))&next_" name ", \"" name "\", sym_" name "_ver}," > structfile; print "extern " ret " (*next_" name ")" argtype ";" > headerfile; print ret " (*next_" name ")" argtype "=tmp_" name ";"> deffile; @@ -68,7 +68,7 @@ BEGIN{ } END{ - print " {NULL, NULL}," > structfile; + print " {NULL, NULL, NULL}," > structfile; print "};" > structfile; print "#endif" > structfile; print "#endif" > tmpffile;