diff --git a/psmisc-22.15-timeout.patch b/psmisc-22.15-timeout.patch index 6436b36..159036a 100644 --- a/psmisc-22.15-timeout.patch +++ b/psmisc-22.15-timeout.patch @@ -117,10 +117,10 @@ index 476fdf1..374a17d 100644 /* * Use /proc/self/mountinfo of modern linux system to determine diff --git a/src/timeout.c b/src/timeout.c -index e69de29..3b582a3 100644 +index e69de29..e79774b 100644 --- a/src/timeout.c +++ b/src/timeout.c -@@ -0,0 +1,215 @@ +@@ -0,0 +1,260 @@ +/* + * timout.c Advanced timeout handling for file system calls + * to avoid deadlocks on remote file shares. @@ -138,9 +138,16 @@ index e69de29..3b582a3 100644 + */ + +#ifndef _GNU_SOURCE -+#define _GNU_SOURCE ++# define _GNU_SOURCE +#endif + ++#ifndef USE_SOCKETPAIR ++# define USE_SOCKETPAIR 1 ++#endif ++ ++#ifdef _FEATURES_H ++# error Include local config.h before any system header file ++#endif +#include "config.h" /* For _FILE_OFFSET_BITS */ + +#include @@ -153,10 +160,24 @@ index e69de29..3b582a3 100644 +#include +#include +#include ++ +#include ++#if USE_SOCKETPAIR ++# include ++# include ++# include ++# ifndef SHUT_RD ++# define SHUT_RD 0 ++# endif ++# ifndef SHUT_WR ++# define SHUT_WR 1 ++# endif ++# undef pipe ++# define pipe(v) (((socketpair(AF_UNIX,SOCK_STREAM,0,v) < 0) || \ ++ (shutdown((v)[1],SHUT_RD) < 0) || (shutdown((v)[0],SHUT_WR) < 0)) ? -1 : 0) ++#endif +#include + -+#include +#include "timeout.h" + +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) @@ -186,16 +207,14 @@ index e69de29..3b582a3 100644 +/* + * The structure used for communication between the processes + */ -+ +typedef struct _handle { -+ size_t len; + int errcode; + struct stat argument; + stat_t function; ++ size_t len; ++ char path[0]; +} attribute((packed)) handle_t; + -+static volatile handle_t handle; -+ +/* + * Using a forked process for doing e.g. stat(2) system call as this + * allows us to send e.g. SIGKILL to this process if it hangs in `D' @@ -205,44 +224,72 @@ index e69de29..3b582a3 100644 + +static volatile pid_t active; +static int pipes[4] = {-1, -1, -1, -1}; ++static char buf[PATH_MAX + sizeof(handle_t) + 1]; ++ ++static void sigchild(int sig attribute((unused))) ++{ ++ pid_t pid = waitpid(active, NULL, WNOHANG|WUNTRACED); ++ if (pid <= 0) ++ return; ++ if (errno == ECHILD) ++ return; ++ active = 0; ++} + +static void attribute((constructor)) start(void) +{ + sigset_t sigset, oldset; -+ char path[PATH_MAX]; -+ handle_t handle; ++ struct sigaction act; + ssize_t in; + ++ if (pipes[1] >= 0) close(pipes[1]); ++ if (pipes[2] >= 0) close(pipes[2]); ++ + if (pipe(&pipes[0])) + goto error; + if (pipe(&pipes[2])) + goto error; ++ ++ memset(&act, 0, sizeof(act)); ++ sigemptyset(&act.sa_mask); ++ act.sa_flags = SA_RESTART; ++ act.sa_handler = sigchild; ++ sigaction(SIGCHLD, &act, 0); ++ + if ((active = fork()) < 0) + goto error; ++ + if (active) { + close(pipes[0]); + close(pipes[3]); + pipes[0] = pipes[3] = -1; + return; + } ++ + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); + sigprocmask(SIG_BLOCK, &sigset, &oldset); + ++ act.sa_handler = SIG_DFL; ++ sigaction(SIGCHLD, &act, 0); ++ + close(pipes[1]); + close(pipes[2]); -+ dup2(pipes[0], 0); -+ dup2(pipes[3], 1); ++ dup2(pipes[0], STDIN_FILENO); ++ dup2(pipes[3], STDOUT_FILENO); + close(pipes[0]); + close(pipes[3]); + pipes[1] = pipes[2] = -1; + pipes[0] = pipes[3] = -1; + -+ while ((in = read(0, &handle, sizeof(handle_t))) == sizeof(handle_t) && -+ (in = read(0, path, handle.len)) == handle.len) { -+ if (handle.function(path, &handle.argument) < 0) -+ handle.errcode = errno; -+ write(1, &handle.errcode, sizeof(handle.errcode)+sizeof(handle.argument)); ++ { ++ handle_t *restrict handle = (void*)&buf[0]; ++ ++ while ((in = read(STDIN_FILENO, handle, sizeof(buf))) > sizeof(handle_t)) { ++ if (handle->function(handle->path, &handle->argument) < 0) ++ handle->errcode = errno; ++ write(STDOUT_FILENO, &handle->errcode, sizeof(handle->errcode)+sizeof(handle->argument)); ++ } + } + sigprocmask(SIG_SETMASK, &oldset, NULL); + exit(0); @@ -255,15 +302,12 @@ index e69de29..3b582a3 100644 + +static void /* attribute((destructor)) */ stop(void) +{ -+ if (active <= 0) -+ return; -+ if (waitpid(active, NULL, WNOHANG) == 0) ++ if (active && waitpid(active, NULL, WNOHANG|WUNTRACED) == 0) + kill(active, SIGKILL); -+ active = 0; +} + +static sigjmp_buf jenv; -+static void sigalarm(int sig attribute((unused))) ++static void sigjump(int sig attribute((unused))) +{ + siglongjmp(jenv, 1); +} @@ -271,61 +315,62 @@ index e69de29..3b582a3 100644 +/* + * External routine + */ -+ +int timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) +{ -+ struct sigaction old_act, new_act; ++ handle_t *restrict handle = (void*)&buf[0]; ++ struct sigaction alrm_act, pipe_act, new_act; + sigset_t sigset, oldset; + -+ if (active <= 0) { /* Oops, last one failed therefore clear status and restart */ -+ int status; -+ waitpid(-1, &status, WNOHANG); ++ if (active <= 0) /* Oops, last one failed therefore clear status and restart */ + start(); -+ } + -+ handle.len = strlen(path) + 1; -+ if (handle.len >= PATH_MAX) { ++ handle->len = strlen(path) + 1; ++ if (handle->len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto error; + } -+ handle.errcode = 0; -+ handle.argument = *argument; -+ handle.function = function; ++ handle->errcode = 0; ++ handle->argument = *argument; ++ handle->function = function; ++ strcpy(handle->path, path); + + sigemptyset(&sigset); + sigaddset(&sigset, SIGALRM); ++ sigaddset(&sigset, SIGPIPE); + sigprocmask(SIG_UNBLOCK, &sigset, &oldset); + + memset(&new_act, 0, sizeof(new_act)); + sigemptyset(&new_act.sa_mask); + new_act.sa_flags = SA_RESETHAND; -+ new_act.sa_handler = sigalarm; + + if (sigsetjmp(jenv, 1)) + goto timed; + -+ sigaction(SIGALRM, &new_act, &old_act); ++ new_act.sa_handler = sigjump; ++ sigaction(SIGALRM, &new_act, &alrm_act); ++ sigaction(SIGPIPE, &new_act, &pipe_act); + alarm(seconds); + -+ write(pipes[1], &handle, sizeof(handle_t)); -+ write(pipes[1], path, handle.len); -+ sched_yield(); -+ read(pipes[2], &handle.errcode, sizeof(handle.errcode)+sizeof(handle.argument)); ++ write(pipes[1], handle, sizeof(handle_t)+handle->len); ++ read(pipes[2], &handle->errcode, sizeof(handle->errcode)+sizeof(handle->argument)); + + alarm(0); -+ sigaction(SIGALRM, &old_act, NULL); ++ sigaction(SIGPIPE, &pipe_act, NULL); ++ sigaction(SIGALRM, &alrm_act, NULL); + -+ if (handle.errcode) { -+ errno = handle.errcode; ++ if (handle->errcode) { ++ errno = handle->errcode; + goto error; + } + -+ *argument = handle.argument; ++ *argument = handle->argument; + sigprocmask(SIG_SETMASK, &oldset, NULL); + + return 0; +timed: + (void) alarm(0); ++ sigaction(SIGPIPE, &pipe_act, NULL); ++ sigaction(SIGALRM, &alrm_act, NULL); + sigprocmask(SIG_SETMASK, &oldset, NULL); + stop(); + errno = ETIMEDOUT; @@ -337,7 +382,7 @@ index e69de29..3b582a3 100644 + * End of timeout.c + */ diff --git a/src/timeout.h b/src/timeout.h -index e69de29..50dd135 100644 +index e69de29..546c13b 100644 --- a/src/timeout.h +++ b/src/timeout.h @@ -0,0 +1,36 @@ diff --git a/psmisc.changes b/psmisc.changes index 2312b3c..789c364 100644 --- a/psmisc.changes +++ b/psmisc.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Oct 7 14:08:31 UTC 2011 - werner@suse.de + +- Make main fuser process more robust against broken pipe and check + for helper process within a SIGCHLD handler + ------------------------------------------------------------------- Wed Oct 5 09:47:38 UTC 2011 - werner@suse.de