Makefile.am | 9 ++- communicate.c | 23 ++++--- configure.ac | 10 ++-- faked.c | 187 ++++++++++++++++++++++++++++++++------------------- libfakeroot.c | 11 +++- scripts/fakeroot.in | 49 ++++++++------ symver.awk | 26 +++++++ test/compare-tar | 4 +- wrapawk | 6 +- 9 files changed, 212 insertions(+), 113 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/communicate.c b/communicate.c index 73b3b48..2676b4d 100644 --- a/communicate.c +++ b/communicate.c @@ -57,7 +57,6 @@ static pthread_mutex_t comm_sd_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /* FAKEROOT_FAKENET */ -#ifdef FAKEROOT_FAKENET static void fail(const char *msg) { if (errno > 0) @@ -67,7 +66,6 @@ static void fail(const char *msg) exit(1); } -#endif /* FAKEROOT_FAKENET */ const char *env_var_set(const char *env){ const char *s; @@ -389,8 +387,7 @@ void semaphore_up(){ while (1) { if (semop(sem_id,&op,1)) { if (errno != EINTR) { - perror("semop(1): encountered an error"); - exit(1); + fail("semop(-1)"); } } else { break; @@ -408,8 +405,7 @@ void semaphore_down(){ while (1) { if (semop(sem_id,&op,1)) { if (errno != EINTR) { - perror("semop(2): encountered an error"); - exit(1); + fail("semop(1)"); } } else { break; @@ -483,10 +479,17 @@ void send_fakem(const struct fake_msg *buf) if(init_get_msg()!=-1){ ((struct fake_msg *)buf)->mtype=1; - r=msgsnd(msg_snd, (struct fake_msg *)buf, - sizeof(*buf)-sizeof(buf->mtype), 0); - if(r==-1) - perror("libfakeroot, when sending message"); + while (1) { + r=msgsnd(msg_snd, (struct fake_msg *)buf, + sizeof(*buf)-sizeof(buf->mtype), 0); + if (r==-1) { + if (errno != EINTR) { + fail("msgsnd"); + } + } else { + break; + } + } } } diff --git a/configure.ac b/configure.ac index a3e9a96..221285e 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]) 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 @@ -130,19 +130,31 @@ fi unset FAKEROOTKEY KEY_PID=`eval $FAKED $FAKEDOPTS $PIPEIN` FAKEROOTKEY=`echo $KEY_PID|cut -d: -f1` -PID=`echo $KEY_PID|cut -d: -f2` +DPID=`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 +if test -z "$FAKEROOTKEY" || test -z "$DPID"; then echo >&2 "fakeroot: error while starting the \`faked' daemon." exit 1 fi +CPID= +cleanup_handler() +{ + trap - EXIT + for p in $CPID $DPID; do + kill -s @signal@ $p 2>/dev/null + if [ "$WAITINTRAP" -ne 0 ]; then + while kill -0 $p 2>/dev/null; do + sleep 0.01 + done + fi + done + exit "$@" +} + +trap 'cleanup_handler $?' EXIT +trap 'cleanup_handler 143' INT QUIT TERM + if test $USEABSLIBPATH -ne 0 ; then LIB=$ABSLIB fi @@ -158,11 +170,8 @@ fi export FAKEROOT_FD_BASE if test -z "$*"; then - FAKEROOTKEY=$FAKEROOTKEY @LDLIBPATHVAR@="$PATHS" @LDEXTRAVAR@ @LDPRELOADVAR@="$LIB" ${SHELL:-/bin/sh} - RESULT=$? -else - FAKEROOTKEY=$FAKEROOTKEY @LDLIBPATHVAR@="$PATHS" @LDEXTRAVAR@ @LDPRELOADVAR@="$LIB" "$@" - RESULT=$? + set -- ${SHELL:-/bin/sh} fi - -exit $RESULT +FAKEROOTKEY=$FAKEROOTKEY @LDLIBPATHVAR@="$PATHS" @LDEXTRAVAR@ @LDPRELOADVAR@="$LIB" "$@" <&0 & +CPID=$! +wait $CPID 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;