#! /bin/sh /usr/share/dpatch/dpatch-run ## 85-fuse-no-kill.dpatch by ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Avoid deadlocks with fuse filesystems. ## DP: ## DP: After stopping all processes all filesystem access must be relative ## DP: and restricted to /proc/. ## DP: ## DP: Do not kill processes that have /dev/fuse open. @DPATCH@ diff -urNad sysvinit-2.86.ds1~/src/killall5.c sysvinit-2.86.ds1/src/killall5.c --- sysvinit-2.86.ds1~/src/killall5.c 2008-04-18 15:39:08.000000000 +0200 +++ sysvinit-2.86.ds1/src/killall5.c 2008-04-18 15:39:55.280398416 +0200 @@ -168,6 +168,7 @@ /* * Read the proc filesystem. + * CWD must be /proc. */ int readproc(int do_stat) { @@ -183,7 +184,7 @@ int pid, f; /* Open the /proc directory. */ - if ((dir = opendir("/proc")) == NULL) { + if ((dir = opendir(".")) == NULL) { nsyslog(LOG_ERR, "cannot opendir(/proc)"); return -1; } @@ -209,10 +210,10 @@ memset(p, 0, sizeof(PROC)); /* Open the status file. */ - snprintf(path, sizeof(path), "/proc/%s/stat", d->d_name); + snprintf(path, sizeof(path), "%s/stat", d->d_name); /* Read SID & statname from it. */ - if ((fp = fopen(path, "r")) != NULL) { + if ((fp = fopen(path, "r")) != NULL) { buf[0] = 0; fgets(buf, sizeof(buf), fp); @@ -226,7 +227,7 @@ if (q == NULL) { p->sid = 0; nsyslog(LOG_ERR, - "can't get program name from %s\n", + "can't get program name from /proc/%s\n", path); free(p); continue; @@ -257,15 +258,15 @@ if (startcode == 0 && endcode == 0) p->kernel = 1; fclose(fp); + } else { /* Process disappeared.. */ free(p); continue; } - snprintf(path, sizeof(path), "/proc/%s/cmdline", d->d_name); + snprintf(path, sizeof(path), "%s/cmdline", d->d_name); if ((fp = fopen(path, "r")) != NULL) { - /* Now read argv[0] */ f = readarg(fp, buf, sizeof(buf)); @@ -325,6 +326,39 @@ return 0; } +/* + * Scan the filedescriptors of pid for /dev/fuse + * CWD must be /proc. + */ +int is_fuse(int pid) { + DIR *dir; + char path[256]; + char buf[256]; + struct dirent *d; + ssize_t len; + + /* Open /proc/pid/fd/ */ + snprintf(path, sizeof(path), "%d/fd", pid); + if ((dir = opendir(path)) != NULL) { + /* Walk through the directory. */ + while ((d = readdir(dir)) != NULL) { + /* check for /dev/fuse */ + snprintf(path, sizeof(path), "%d/fd/%s", + pid, d->d_name); + if ((len = readlink(path, buf, sizeof(buf))) > 0) { + if (strncmp("/dev/fuse", buf, len) == 0) { + /* Fuse filesystem */ + return 1; + } + } + } + closedir(dir); + } + + /* Not a fuse filesystem */ + return 0; +} + PIDQ_HEAD *init_pid_q(PIDQ_HEAD *q) { q->head = q->next = q->tail = NULL; @@ -618,6 +652,10 @@ /* First get the /proc filesystem online. */ mount_proc(); + if (chdir("/proc") == -1) { + nsyslog(LOG_ERR, "chdir /proc failed"); + return(1); + } /* * Ignoring SIGKILL and SIGSTOP do not make sense, but @@ -642,11 +680,12 @@ return(1); } - /* Now kill all processes except init (pid 1) and our session. */ + /* Now kill all processes except init (pid 1), our session + * and fuse filesystems. */ sid = (int)getsid(0); pid = (int)getpid(); for (p = plist; p; p = p->next) - if (p->pid != 1 && p->pid != pid && p->sid != sid && !p->kernel) { + if (p->pid != 1 && p->pid != pid && p->sid != sid && !p->kernel && !is_fuse(p->pid)) { kill(p->pid, sig); retval = 0; }