From fe5380708301984867c35253fe43078987c5e07d Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Fri, 25 Apr 2014 10:02:11 +0000 Subject: [PATCH] Accepting request 231322 from home:oertel:branches:Base:System - add patch to fix fuser -M option active all the time (bnc#874983) psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch OBS-URL: https://build.opensuse.org/request/show/231322 OBS-URL: https://build.opensuse.org/package/show/Base:System/psmisc?expand=0&rev=72 --- psmisc-22.20-upstream.patch | 861 ------------------ psmisc-22.20.tar.gz | 3 - ...cc55b4d08851faba46635d737b24d016665b.patch | 34 + psmisc.changes | 6 + psmisc.spec | 3 + 5 files changed, 43 insertions(+), 864 deletions(-) delete mode 100644 psmisc-22.20-upstream.patch delete mode 100644 psmisc-22.20.tar.gz create mode 100644 psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch diff --git a/psmisc-22.20-upstream.patch b/psmisc-22.20-upstream.patch deleted file mode 100644 index 501db88..0000000 --- a/psmisc-22.20-upstream.patch +++ /dev/null @@ -1,861 +0,0 @@ - ChangeLog | 6 ++ - configure.ac | 11 ++++ - src/fuser.c | 182 +++++++++++++++------------------------------------------ - src/fuser.h | 4 +- - src/lists.h | 132 +++++++++++++++++++++++++++++++++++++++-- - src/timeout.c | 163 ++++++++++++++++++++++++++++++++++++++++++--------- - src/timeout.h | 13 ++++- - 7 files changed, 340 insertions(+), 171 deletions(-) - -diff --git ChangeLog ChangeLog -index 4e3f348..d5cb9ec 100644 ---- ChangeLog -+++ ChangeLog -@@ -1,3 +1,9 @@ -+ * Make usage of linked lists of devices found in -+ /proc/self/mountinfo optional -+ * Make timeout() in timeout.c work with shared mmap to -+ reduce the load due write/read the stat buffers -+ * Add list_sort() to lists.h to be able to sort lists -+ - Changes in 22.21 - ================ - * Missing comma in fuser(1) added Debian #702391 -diff --git configure.ac configure.ac -index 9df639d..cb03ba9 100644 ---- configure.ac -+++ configure.ac -@@ -42,6 +42,17 @@ if test "$enable_timeout_stat" = "static"; then - fi - AM_CONDITIONAL([WANT_TIMEOUT_STAT], [test "$enable_timeout_stat" = "static"]) - -+# Use string search for network based file systems but only if the system -+# has /proc/self/mountinfo -+AC_SUBST([WITH_MOUNTINFO_LIST]) -+AC_ARG_ENABLE([mountinfo_list], -+ [AS_HELP_STRING([--enable-mountinfo-list], [Use the list in /proc/self/mountinfo to replace stat(2) syscall on network file systems shares])], -+ [enable_mountinfo_list="yes"], -+ [enable_mountinfo_list="no"]) -+if test "$enable_mountinfo_list" = "yes" -a -e /proc/self/mountinfo ; then -+ AC_DEFINE([WITH_MOUNTINFO_LIST], [1], [Use list in /proc/self/mountinfo to replace stat calls]) -+fi -+ - # Enable hardened compile and link flags - AC_ARG_ENABLE([harden_flags], - [AS_HELP_STRING([--disable-harden-flags], [disable hardened compilier and linker flags])], -diff --git src/fuser.c src/fuser.c -index 0c773fe..8d04ff5 100644 ---- src/fuser.c -+++ src/fuser.c -@@ -58,6 +58,7 @@ - #include "fuser.h" - #include "signals.h" - #include "i18n.h" -+#include "timeout.h" - - //#define DEBUG 1 - -@@ -104,25 +105,14 @@ static void debug_match_lists(struct names *names_head, - struct device_list *dev_head); - #endif - --#ifdef _LISTS_H -+#if defined(WITH_MOUNTINFO_LIST) - static void clear_mntinfo(void) __attribute__ ((__destructor__)); - static void init_mntinfo(void) __attribute__ ((__constructor__)); --static dev_t device(const char *path); -+static int mntstat(const char *path, struct stat *buf); - #endif -+static stat_t thestat = stat; - static char *expandpath(const char *path); - --#ifdef WITH_TIMEOUT_STAT --#if (WITH_TIMEOUT_STAT == 2) --#include "timeout.h" --#else --typedef int (*stat_t) (const char *, struct stat *); --static int timeout(stat_t func, const char *path, struct stat *buf, -- unsigned int seconds); --#endif --#else --#define timeout(func,path,buf,dummy) (func)((path),(buf)) --#endif /* WITH_TIMEOUT_STAT */ -- - static void usage(const char *errormsg) - { - if (errormsg != NULL) -@@ -191,10 +181,6 @@ scan_procs(struct names *names_head, struct inode_list *ino_head, - struct stat *cwd_stat = NULL; - struct stat *exe_stat = NULL; - struct stat *root_stat = NULL; --#ifdef _LISTS_H -- char path[256] = "/proc/", *slash; -- ssize_t len; --#endif - - if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */ - continue; -@@ -204,30 +190,12 @@ scan_procs(struct names *names_head, struct inode_list *ino_head, - continue; - uid = getpiduid(pid); - --#ifdef _LISTS_H -- strcpy(&path[6], topproc_dent->d_name); -- len = strlen(path); -- slash = &path[len]; -- -- *slash = '\0'; -- strcat(slash, "/cwd"); -- cwd_dev = device(path); -- -- *slash = '\0'; -- strcat(slash, "/exe"); -- exe_dev = device(path); -- -- *slash = '\0'; -- strcat(slash, "/root"); -- root_dev = device(path); --#else - cwd_stat = get_pidstat(pid, "cwd"); - exe_stat = get_pidstat(pid, "exe"); - root_stat = get_pidstat(pid, "root"); - cwd_dev = cwd_stat ? cwd_stat->st_dev : 0; - exe_dev = exe_stat ? exe_stat->st_dev : 0; - root_dev = root_stat ? root_stat->st_dev : 0; --#endif - - /* Scan the devices */ - for (dev_tmp = dev_head; dev_tmp != NULL; -@@ -463,7 +431,7 @@ add_special_proc(struct names *name_list, const char ptype, const uid_t uid, - } - - int parse_file(struct names *this_name, struct inode_list **ino_list, -- const char opts) -+ const opt_type opts) - { - char *new = expandpath(this_name->filename); - if (new) { -@@ -471,8 +439,7 @@ int parse_file(struct names *this_name, struct inode_list **ino_list, - free(this_name->filename); - this_name->filename = strdup(new); - } -- -- if (timeout(stat, this_name->filename, &(this_name->st), 5) != 0) { -+ if (timeout(thestat, this_name->filename, &(this_name->st), 5) != 0) { - if (errno == ENOENT) - fprintf(stderr, - _("Specified filename %s does not exist.\n"), -@@ -514,7 +481,7 @@ parse_unixsockets(struct names *this_name, struct inode_list **ino_list, - - int - parse_mounts(struct names *this_name, struct device_list **dev_list, -- const char opts) -+ const opt_type opts) - { - dev_t match_device; - -@@ -992,6 +959,10 @@ int main(int argc, char *argv[]) - break; - case 'c': - opts |= OPT_MOUNTS; -+#if defined(WITH_MOUNTINFO_LIST) -+ thestat = mntstat; -+#endif -+ read_proc_mounts(&mounts); - break; - case 'f': - /* ignored */ -@@ -1010,6 +981,9 @@ int main(int argc, char *argv[]) - return 0; - case 'm': - opts |= OPT_MOUNTS; -+#if defined(WITH_MOUNTINFO_LIST) -+ thestat = mntstat; -+#endif - read_proc_mounts(&mounts); - break; - case 'M': -@@ -1378,7 +1352,7 @@ static struct stat *get_pidstat(const pid_t pid, const char *filename) - if ((st = (struct stat *)malloc(sizeof(struct stat))) == NULL) - return NULL; - snprintf(pathname, 256, "/proc/%d/%s", pid, filename); -- if (timeout(stat, pathname, st, 5) != 0) { -+ if (timeout(thestat, pathname, st, 5) != 0) { - free(st); - return NULL; - } -@@ -1410,7 +1384,7 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - snprintf(filepath, MAX_PATHNAME, "/proc/%d/%s/%s", - pid, dirname, direntry->d_name); - -- if (timeout(stat, filepath, &st, 5) != 0) { -+ if (timeout(thestat, filepath, &st, 5) != 0) { - if (errno != ENOENT) { - fprintf(stderr, _("Cannot stat file %s: %s\n"), - filepath, strerror(errno)); -@@ -1449,7 +1423,7 @@ check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, - if (thedev != ino_tmp->device) - continue; - if (!st.st_ino -- && timeout(stat, filepath, &st, 5) != 0) { -+ && timeout(thestat, filepath, &st, 5) != 0) { - fprintf(stderr, - _("Cannot stat file %s: %s\n"), - filepath, strerror(errno)); -@@ -1519,7 +1493,7 @@ static uid_t getpiduid(const pid_t pid) - - if (snprintf(pathname, MAX_PATHNAME, "/proc/%d", pid) < 0) - return 0; -- if (timeout(stat, pathname, &st, 5) != 0) -+ if (timeout(thestat, pathname, &st, 5) != 0) - return 0; - return st.st_uid; - } -@@ -1555,7 +1529,7 @@ void fill_unix_cache(struct unixsocket_list **unixsocket_head) - path = scanned_path; - if (*scanned_path == '@') - scanned_path++; -- if (timeout(stat, scanned_path, &st, 5) < 0) { -+ if (timeout(thestat, scanned_path, &st, 5) < 0) { - free(path); - continue; - } -@@ -1700,7 +1674,7 @@ scan_knfsd(struct names *names_head, struct inode_list *ino_head, - if ((find_space = strpbrk(line, " \t")) == NULL) - continue; - *find_space = '\0'; -- if (timeout(stat, line, &st, 5) != 0) { -+ if (timeout(thestat, line, &st, 5) != 0) { - continue; - } - /* Scan the devices */ -@@ -1744,7 +1718,7 @@ scan_mounts(struct names *names_head, struct inode_list *ino_head, - if ((find_space = strchr(find_mountp, ' ')) == NULL) - continue; - *find_space = '\0'; -- if (timeout(stat, find_mountp, &st, 5) != 0) { -+ if (timeout(thestat, find_mountp, &st, 5) != 0) { - continue; - } - /* Scan the devices */ -@@ -1791,7 +1765,7 @@ scan_swaps(struct names *names_head, struct inode_list *ino_head, - if (*find_space == '\0') - continue; - } -- if (timeout(stat, line, &st, 5) != 0) { -+ if (timeout(thestat, line, &st, 5) != 0) { - continue; - } - /* Scan the devices */ -@@ -1812,73 +1786,7 @@ scan_swaps(struct names *names_head, struct inode_list *ino_head, - fclose(fp); - } - --/* -- * Execute stat(2) system call with timeout to avoid deadlock -- * on network based file systems. -- */ --#if defined(WITH_TIMEOUT_STAT) && (WITH_TIMEOUT_STAT == 1) -- --static sigjmp_buf jenv; -- --static void sigalarm(int sig) --{ -- if (sig == SIGALRM) -- siglongjmp(jenv, 1); --} -- --static int --timeout(stat_t func, const char *path, struct stat *buf, unsigned int seconds) --{ -- pid_t pid = 0; -- int ret = 0, pipes[4]; -- ssize_t len; -- -- if (pipe(&pipes[0]) < 0) -- goto err; -- switch ((pid = fork())) { -- case -1: -- close(pipes[0]); -- close(pipes[1]); -- goto err; -- case 0: -- (void)signal(SIGALRM, SIG_DFL); -- close(pipes[0]); -- if ((ret = func(path, buf)) == 0) -- do -- len = write(pipes[1], buf, sizeof(struct stat)); -- while (len < 0 && errno == EINTR); -- close(pipes[1]); -- exit(ret); -- default: -- close(pipes[1]); -- if (sigsetjmp(jenv, 1)) { -- (void)alarm(0); -- (void)signal(SIGALRM, SIG_DFL); -- if (waitpid(0, (int *)0, WNOHANG) == 0) -- kill(pid, SIGKILL); -- errno = ETIMEDOUT; -- seconds = 1; -- goto err; -- } -- (void)signal(SIGALRM, sigalarm); -- (void)alarm(seconds); -- if (read(pipes[0], buf, sizeof(struct stat)) == 0) { -- errno = EFAULT; -- ret = -1; -- } -- (void)alarm(0); -- (void)signal(SIGALRM, SIG_DFL); -- close(pipes[0]); -- waitpid(pid, NULL, 0); -- break; -- } -- return ret; -- err: -- return -1; --} --#endif /* WITH_TIMEOUT_STAT */ -- --#ifdef _LISTS_H -+#if defined(WITH_MOUNTINFO_LIST) - /* - * Use /proc/self/mountinfo of modern linux system to determine - * the device numbers of the mount points. Use this to avoid the -@@ -1967,42 +1875,46 @@ static void init_mntinfo(void) - /* - * Determine device of links below /proc/ - */ --static dev_t device(const char *path) -+static int mntstat(const char *path, struct stat *buf) - { - char name[PATH_MAX + 1]; - const char *use; - ssize_t nlen; - list_t *ptr; - -- if ((nlen = readlink(path, name, PATH_MAX)) < 0) { -- nlen = strlen(path); -- use = &path[0]; -- } else { -- name[nlen] = '\0'; -- use = &name[0]; -- } -- -- if (*use != '/') { /* special file (socket, pipe, inotify) */ -- struct stat st; -- if (timeout(stat, path, &st, 5) != 0) -- return (dev_t) - 1; -- return st.st_dev; -+ if ((use = realpath(path, name)) == NULL || *use != '/') -+ { -+ if (errno == ENOENT) -+ return -1; -+ /* -+ * Could be a special file (socket, pipe, inotify) -+ */ -+ errno = 0; -+ return stat(path, buf); - } - -+ nlen = strlen(use); - list_for_each(ptr, &mntinfo) { - mntinfo_t *mnt = list_entry(ptr, mntinfo_t); - if (nlen < mnt->nlen) - continue; -- if (mnt->nlen == 1) /* root fs is the last entry */ -- return mnt->dev; -+ if (mnt->nlen == 1) { /* root fs is the last entry */ -+ buf->st_dev = mnt->dev; -+ buf->st_ino = 0; -+ return 0; -+ } - if (use[mnt->nlen] != '\0' && use[mnt->nlen] != '/') - continue; -- if (strncmp(use, mnt->mpoint, mnt->nlen) == 0) -- return mnt->dev; -+ if (strncmp(use, mnt->mpoint, mnt->nlen) == 0) { -+ buf->st_dev = mnt->dev; -+ buf->st_ino = 0; -+ return 0; -+ } - } -- return (dev_t) - 1; -+ errno = ENOENT; -+ return -1; - } --#endif /* _LISTS_H */ -+#endif /* WITH_MOUNTINFO_LIST */ - - /* - * Somehow the realpath(3) glibc function call, nevertheless -diff --git src/fuser.h src/fuser.h -index 242ce19..07488bc 100644 ---- src/fuser.h -+++ src/fuser.h -@@ -86,7 +86,7 @@ struct mount_list { - struct mount_list *next; - }; - --#if defined (__GNUC__) && defined(__OPTIMIZE__) && !defined (__CYGWIN__) -+#if defined (__GNUC__) && defined(WITH_MOUNTINFO_LIST) - # include "lists.h" - typedef struct mntinfo_s { - list_t this; -@@ -95,6 +95,8 @@ typedef struct mntinfo_s { - size_t nlen; - char *mpoint; - } mntinfo_t; -+#else -+# undef WITH_MOUNTINFO_LIST - #endif - - #define NAMESPACE_FILE 0 -diff --git src/lists.h src/lists.h -index ae8929e..bd371a4 100644 ---- src/lists.h -+++ src/lists.h -@@ -1,10 +1,10 @@ - /* -- * lists.h Simple doubly linked list implementation, -- * based on and . -+ * lists.h Simple doubly linked list implementation, based on -+ * , , and lib/list_sort.c - * -- * Version: 0.1 01-Feb-2011 Fink -+ * Version: 0.2 11-Dec-2012 Fink - * -- * Copyright 2011 Werner Fink, 2005 SUSE LINUX Products GmbH, Germany. -+ * Copyright 2011,2012 Werner Fink, 2005,2012 SUSE LINUX Products GmbH, Germany. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -246,4 +246,128 @@ static inline void move_tail(list_t *restrict entry, list_t *restrict head) - #define np_list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); pos = pos->prev) - -+#define MAX_LIST_LENGTH_BITS 20 -+ -+/* -+ * Returns a list organized in an intermediate format suited -+ * to chaining of merge() calls: null-terminated, no reserved or -+ * sentinel head node, "prev" links not maintained. -+ */ -+static inline list_t *merge(int (*cmp)(list_t *a, list_t *b), list_t *a, list_t *b) -+{ -+ list_t head, *tail = &head; -+ while (a && b) { -+ /* if equal, take 'a' -- important for sort stability */ -+ if ((*cmp)(a, b) <= 0) { -+ tail->next = a; -+ a = a->next; -+ } else { -+ tail->next = b; -+ b = b->next; -+ } -+ tail = tail->next; -+ } -+ tail->next = a ? a : b; -+ return head.next; -+} -+ -+/* -+ * Combine final list merge with restoration of standard doubly-linked -+ * list structure. This approach duplicates code from merge(), but -+ * runs faster than the tidier alternatives of either a separate final -+ * prev-link restoration pass, or maintaining the prev links -+ * throughout. -+ */ -+static inline void merge_and_restore_back_links(int (*cmp)(list_t *a, list_t *b), list_t *head, list_t *a, list_t *b) -+{ -+ list_t *tail = head; -+ -+ while (a && b) { -+ /* if equal, take 'a' -- important for sort stability */ -+ if ((*cmp)(a, b) <= 0) { -+ tail->next = a; -+ a->prev = tail; -+ a = a->next; -+ } else { -+ tail->next = b; -+ b->prev = tail; -+ b = b->next; -+ } -+ tail = tail->next; -+ } -+ tail->next = a ? a : b; -+ -+ do { -+ /* -+ * In worst cases this loop may run many iterations. -+ * Continue callbacks to the client even though no -+ * element comparison is needed, so the client's cmp() -+ * routine can invoke cond_resched() periodically. -+ */ -+ (*cmp)(tail->next, tail->next); -+ -+ tail->next->prev = tail; -+ tail = tail->next; -+ } while (tail->next); -+ -+ tail->next = head; -+ head->prev = tail; -+} -+ -+ -+/** -+ * list_sort - sort a list -+ * @head: the list to sort -+ * @cmp: the elements comparison function -+ * -+ * This function implements "merge sort", which has O(nlog(n)) -+ * complexity. -+ * -+ * The comparison function @cmp must return a negative value if @a -+ * should sort before @b, and a positive value if @a should sort after -+ * @b. If @a and @b are equivalent, and their original relative -+ * ordering is to be preserved, @cmp must return 0. -+ */ -+static inline void list_sort(list_t *head, int (*cmp)(list_t *a, list_t *b)) -+{ -+ list_t *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists -+ -- last slot is a sentinel */ -+ size_t lev; /* index into part[] */ -+ size_t max_lev = 0; -+ list_t *list; -+ -+ if (list_empty(head)) -+ return; -+ -+ memset(part, 0, sizeof(part)); -+ -+ head->prev->next = NULL; -+ list = head->next; -+ -+ while (list) { -+ list_t *cur = list; -+ list = list->next; -+ cur->next = NULL; -+ -+ for (lev = 0; part[lev]; lev++) { -+ cur = merge(cmp, part[lev], cur); -+ part[lev] = NULL; -+ } -+ if (lev > max_lev) { -+ /* list passed to list_sort() too long for efficiency */ -+ if (lev >= MAX_LIST_LENGTH_BITS) -+ lev--; -+ max_lev = lev; -+ } -+ part[lev] = cur; -+ } -+ -+ for (lev = 0; lev < max_lev; lev++) { -+ if (part[lev]) -+ list = merge(cmp, part[lev], list); -+ } -+ -+ merge_and_restore_back_links(cmp, head, part[max_lev], list); -+} -+ - #endif /* _LISTS_H */ -diff --git src/timeout.c src/timeout.c -index 1fe0354..ca4a7cd 100644 ---- src/timeout.c -+++ src/timeout.c -@@ -2,9 +2,9 @@ - * timout.c Advanced timeout handling for file system calls - * to avoid deadlocks on remote file shares. - * -- * Version: 0.1 07-Sep-2011 Fink -+ * Version: 0.2 11-Dec-2012 Fink - * -- * Copyright 2011 Werner Fink, 2011 SUSE LINUX Products GmbH, Germany. -+ * Copyright 2011,2012 Werner Fink, 2011,2012 SUSE LINUX Products GmbH, Germany. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -18,26 +18,29 @@ - # 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 "config.h" -+ -+#ifndef WITH_TIMEOUT_STAT -+# define WITH_TIMEOUT_STAT 0 -+#endif -+ -+#ifndef USE_SOCKETPAIR -+# define USE_SOCKETPAIR 1 -+#endif - - #include --#include - #include - #include - #include - #include -+#include - #include - #include - #include - #include -- - #include - #if USE_SOCKETPAIR - # include -@@ -86,6 +89,15 @@ - # define strcpy(d,s) __builtin_strcpy((d),(s)) /* Without boundary check please */ - #endif - -+#if WITH_TIMEOUT_STAT -+static sigjmp_buf jenv; -+static void sigjump(int sig attribute((unused))) -+{ -+ siglongjmp(jenv, 1); -+} -+#endif -+ -+#if WITH_TIMEOUT_STAT == 2 - /* - * The structure used for communication between the processes - */ -@@ -106,7 +118,8 @@ typedef struct _handle { - - static volatile pid_t active; - static int pipes[4] = {-1, -1, -1, -1}; --static char buf[PATH_MAX + sizeof(handle_t) + 1]; -+static handle_t *restrict handle; -+static const size_t buflen = PATH_MAX+sizeof(handle_t)+1; - - static void sigchild(int sig attribute((unused))) - { -@@ -122,6 +135,7 @@ static void attribute((constructor)) start(void) - { - sigset_t sigset, oldset; - struct sigaction act; -+ char sync[1]; - ssize_t in; - - if (pipes[1] >= 0) close(pipes[1]); -@@ -138,6 +152,12 @@ static void attribute((constructor)) start(void) - act.sa_handler = sigchild; - sigaction(SIGCHLD, &act, 0); - -+ if (!handle) -+ handle = mmap(NULL, buflen, PROT_READ|PROT_WRITE, -+ MAP_ANONYMOUS|MAP_SHARED, -1, 0); -+ if (handle == MAP_FAILED) -+ goto error; -+ - if ((active = fork()) < 0) - goto error; - -@@ -164,16 +184,22 @@ static void attribute((constructor)) start(void) - pipes[1] = pipes[2] = -1; - pipes[0] = pipes[3] = -1; - -- { -- 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)); -- memset(handle, 0, sizeof(handle_t)); -+ while ((in = read(STDIN_FILENO, &sync, sizeof(sync))) != 0) { -+ ssize_t out; -+ if (in < 0) { -+ if (errno == EINTR) -+ continue; -+ break; - } -+ if (!handle) -+ break; -+ if (handle->function(handle->path, &handle->argument) < 0) -+ handle->errcode = errno; -+ do -+ out = write(STDOUT_FILENO, &sync, sizeof(sync)); -+ while (out < 0 && errno == EINTR); - } -+ - sigprocmask(SIG_SETMASK, &oldset, NULL); - exit(0); - error: -@@ -181,6 +207,9 @@ error: - if (pipes[1] >= 0) close(pipes[1]); - if (pipes[2] >= 0) close(pipes[2]); - if (pipes[3] >= 0) close(pipes[3]); -+ if (handle && handle != MAP_FAILED) -+ munmap(handle, buflen); -+ handle = NULL; - } - - static void /* attribute((destructor)) */ stop(void) -@@ -189,24 +218,24 @@ static void /* attribute((destructor)) */ stop(void) - kill(active, SIGKILL); - } - --static sigjmp_buf jenv; --static void sigjump(int sig attribute((unused))) --{ -- siglongjmp(jenv, 1); --} -- - /* - * External routine -+ * -+ * Execute stat(2) system call with timeout to avoid deadlock -+ * on network based file systems. -+ * - */ --int timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) -+int -+timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) - { -- handle_t *restrict handle = (void*)&buf[0]; - struct sigaction alrm_act, pipe_act, new_act; - sigset_t sigset, oldset; -+ char sync[1] = "x"; - - if (active <= 0) /* Oops, last one failed therefore clear status and restart */ - start(); -- -+ if (!handle) /* No shared memory area */ -+ return function(path, argument); - memset(handle, 0, sizeof(handle_t)); - handle->len = strlen(path) + 1; - if (handle->len >= PATH_MAX) { -@@ -235,8 +264,8 @@ int timeout(stat_t function, const char *path, struct stat *restrict argument, t - sigaction(SIGPIPE, &new_act, &pipe_act); - alarm(seconds); - -- write(pipes[1], handle, sizeof(handle_t)+handle->len); -- read(pipes[2], &handle->errcode, sizeof(handle->errcode)+sizeof(handle->argument)); -+ write(pipes[1], &sync, sizeof(sync)); -+ read(pipes[2], &sync, sizeof(sync)); - - alarm(0); - sigaction(SIGPIPE, &pipe_act, NULL); -@@ -261,6 +290,82 @@ timed: - error: - return -1; - } -+#elif WITH_TIMEOUT_STAT == 1 -+/* -+ * External routine -+ * -+ * Execute stat(2) system call with timeout to avoid deadlock -+ * on network based file systems. -+ * -+ */ -+int -+timeout(stat_t function, const char *path, struct stat *restrict argument, time_t seconds) -+{ -+ struct sigaction alrm_act, pipe_act, new_act; -+ sigset_t sigset, oldset; -+ int ret = 0, pipes[4]; -+ pid_t pid = 0; -+ ssize_t len; -+ -+ if (pipe(&pipes[0]) < 0) -+ goto error; -+ switch ((pid = fork())) { -+ case -1: -+ close(pipes[0]); -+ close(pipes[1]); -+ goto error; -+ case 0: -+ new_act.sa_handler = SIG_DFL; -+ sigaction(SIGALRM, &new_act, NULL); -+ close(pipes[0]); -+ if ((ret = function(path, argument)) == 0) -+ do -+ len = write(pipes[1], argument, sizeof(struct stat)); -+ while (len < 0 && errno == EINTR); -+ close(pipes[1]); -+ exit(ret); -+ default: -+ close(pipes[1]); -+ -+ 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); -+ -+ if (sigsetjmp(jenv, 1)) -+ goto timed; -+ -+ new_act.sa_handler = sigjump; -+ sigaction(SIGALRM, &new_act, &alrm_act); -+ sigaction(SIGPIPE, &new_act, &pipe_act); -+ alarm(seconds); -+ if (read(pipes[0], argument, sizeof(struct stat)) == 0) { -+ errno = EFAULT; -+ ret = -1; -+ } -+ (void)alarm(0); -+ sigaction(SIGPIPE, &pipe_act, NULL); -+ sigaction(SIGALRM, &alrm_act, NULL); -+ -+ close(pipes[0]); -+ waitpid(pid, NULL, 0); -+ break; -+ } -+ return ret; -+timed: -+ (void)alarm(0); -+ sigaction(SIGPIPE, &pipe_act, NULL); -+ sigaction(SIGALRM, &alrm_act, NULL); -+ if (waitpid(0, NULL, WNOHANG) == 0) -+ kill(pid, SIGKILL); -+ errno = ETIMEDOUT; -+error: -+ return -1; -+} -+#endif - - /* - * End of timeout.c -diff --git src/timeout.h src/timeout.h -index 546c13b..f372297 100644 ---- src/timeout.h -+++ src/timeout.h -@@ -17,7 +17,11 @@ - #ifndef _TIMEOUT_H - #define _TIMEOUT_H - --#include "config.h" /* For _FILE_OFFSET_BITS */ -+#include "config.h" -+ -+#ifndef WITH_TIMEOUT_STAT -+# define WITH_TIMEOUT_STAT 0 -+#endif - - #include - #include -@@ -30,7 +34,12 @@ - # endif - #endif - --typedef int (*stat_t)(const char *, struct stat *restrict); -+typedef int (*stat_t)(const char *, struct stat *); -+ -+#if WITH_TIMEOUT_STAT > 0 - extern int timeout(stat_t, const char *, struct stat *restrict, time_t); -+#else -+# define timeout(func,path,buf,dummy) (func)((path),(buf)) -+#endif - - #endif diff --git a/psmisc-22.20.tar.gz b/psmisc-22.20.tar.gz deleted file mode 100644 index 86b8d54..0000000 --- a/psmisc-22.20.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b17224e2385f6a799ffebba27eb7870771d42555e86814ef56b6d7e955765514 -size 432501 diff --git a/psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch b/psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch new file mode 100644 index 0000000..8385acf --- /dev/null +++ b/psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch @@ -0,0 +1,34 @@ +commit 3638cc55b4d08851faba46635d737b24d016665b +Author: Brad Jorsch +Date: Fri Feb 28 21:55:02 2014 +1100 + + Typo in fuser makes -M on all the time + + Brad found that fuser had the -M option on all the time. + A simple but significant typo caused this, thanks the the patch. + + Bug-Debian: http://bugs.debian.org/740275 + + Signed-off-by: Craig Small + +================================================================================ +--- psmisc-22.21/ChangeLog ++++ psmisc-22.21/ChangeLog +@@ -1,3 +1,6 @@ ++Changes in 22.22 ++================ ++ * Fixed typo in fuser which has -M on Debian #740275 + * Make usage of linked lists of devices found in + /proc/self/mountinfo optional + * Make timeout() in timeout.c work with shared mmap to +--- psmisc-22.21/src/fuser.c ++++ psmisc-22.21/src/fuser.c +@@ -1151,7 +1151,7 @@ + usage(_("No process specification given")); + + /* Check if -M flag was used and if so check mounts */ +- if (opts * OPT_ISMOUNTPOINT) { ++ if (opts & OPT_ISMOUNTPOINT) { + check_mountpoints(&mounts, &names_head, &names_tail); + } + diff --git a/psmisc.changes b/psmisc.changes index 2396d08..ffe23ab 100644 --- a/psmisc.changes +++ b/psmisc.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Apr 25 00:59:39 CEST 2014 - ro@suse.de + +- add patch to fix fuser -M option active all the time (bnc#874983) + psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch + ------------------------------------------------------------------- Mon Mar 24 16:01:51 UTC 2014 - werner@suse.de diff --git a/psmisc.spec b/psmisc.spec index ff47a3b..adf9243 100644 --- a/psmisc.spec +++ b/psmisc.spec @@ -35,6 +35,8 @@ Patch0: %name-22.21.dif Patch1: %name-22.12-tigetstr.patch Patch2: %name-22.21-pstree.patch Patch42: %{name}-22.21-upstream.patch +# PATCH-FIX-UPSTREAM psmisc-git-3638cc55b4d08851faba46635d737b24d016665b.patch bnc#874983 +Patch43: %{name}-git-3638cc55b4d08851faba46635d737b24d016665b.patch %define nopeek s390 s390x ia64 %sparc hppa aarch64 @@ -54,6 +56,7 @@ processes that are using specified files or filesystems. %patch1 -p0 -b .tigetstr %patch2 -p0 -b .pstree %patch0 -p0 -b .0 +%patch43 -p1 -b .fuserfix %build autoreconf -fi