--- src/killall5.c +++ src/killall5.c 2009-03-11 14:13:21.708001809 +0100 @@ -40,6 +40,8 @@ #include #include #include +#include +#include char *Version = "@(#)killall5 2.86 31-Jul-2004 miquels@cistron.nl"; @@ -56,7 +58,8 @@ typedef struct proc { dev_t dev; /* Device it is on */ pid_t pid; /* Process ID. */ int sid; /* Session ID. */ - int kernel; /* Kernel thread or zombie. */ + char kernel; /* Kernel thread or zombie. */ + char nfs; /* Binary is loacted on NFS part. */ struct proc *next; /* Pointer to next struct. */ } PROC; @@ -73,9 +76,20 @@ typedef struct { PIDQ *next; } PIDQ_HEAD; +typedef struct nfs +{ + struct nfs *next; /* Pointer to next struct. */ + struct nfs *prev; /* Pointer to previous st. */ + char * name; + size_t nlen; +} NFS; + /* List of processes. */ PROC *plist; +/* List of NFS mountes partitions. */ +NFS *nlist; + /* Did we stop all processes ? */ int sent_sigstop; @@ -152,6 +166,116 @@ int mount_proc(void) return did_mount; } +static inline int isnetfs(const char * type) +{ + static const char* netfs[] = {"nfs", "nfs4", "smbfs", "cifs", "afs", "ncpfs", (char*)0}; + int n; + for (n = 0; netfs[n]; n++) + if (!strcasecmp(netfs[n], type)) + return 1; + return 0; +} + +/* + * Remember all NFS typed partitions. + */ +void init_nfs(void) +{ + struct stat st; + struct mntent * ent; + FILE * mnt; + + nlist = (NFS*)0; + + if (stat("/proc/version", &st) < 0) + return; + if ((mnt = setmntent("/proc/mounts", "r")) == (FILE*)0) + return; + + while ((ent = getmntent(mnt))) { + if (isnetfs(ent->mnt_type)) { + NFS * p = (NFS*)xmalloc(sizeof(NFS)); + p->name = (char*)xmalloc(strlen(ent->mnt_dir)+1); + strcpy(p->name, ent->mnt_dir); + p->nlen = strlen(p->name); + if (nlist) + nlist->prev = p; + p->next = nlist; + p->prev = (NFS*)0; + nlist = p; + } + } + + endmntent(mnt); +} + +/* + * Check path is located on a NFS partition. + */ +int check4nfs(const char * path, char * real) +{ + char buf[PATH_MAX+1]; + const char *curr; + int deep = MAXSYMLINKS; + + if (!nlist) return 0; + + curr = path; + do { + const char *prev; + int len; + + if ((prev = strdupa(curr)) == NULL) { + nsyslog(LOG_ERR, "strdupa(): %s\n", strerror(errno)); + return 0; + } + + errno = 0; + if ((len = readlink(curr, buf, PATH_MAX)) < 0) + break; + buf[len] = '\0'; + + if (buf[0] != '/') { + const char *slash; + + if ((slash = strrchr(prev, '/'))) { + size_t off = slash - prev + 1; + + if (off + len > PATH_MAX) + len = PATH_MAX - off; + + memmove(&buf[off], &buf[0], len + 1); + memcpy(&buf[0], prev, off); + } + } + curr = &buf[0]; + + if (deep-- <= 0) return 0; + + } while (1); + + if (real) strcpy(real, curr); + + if (errno == EINVAL) { + const size_t nlen = strlen(curr); + NFS *p, *n, *l; + n = nlist; + l = (NFS*)0; + for (p = nlist; n; p = n) { + l = p->prev; + n = p->next; + if (nlen < p->nlen) + continue; + if (curr[p->nlen] != '\0' && curr[p->nlen] != '/') + continue; + if (!strncmp(curr, p->name, p->nlen)) + return 1; + } + } + + return 0; +} + int readarg(FILE *fp, char *buf, int sz) { int c = 0, f = 0; @@ -173,8 +297,8 @@ int readproc() PROC *p, *n; struct dirent *d; struct stat st; - char path[256]; - char buf[256]; + char path[PATH_MAX+1]; + char buf[PATH_MAX+1]; char *s, *q; unsigned long startcode, endcode; int pid, f; @@ -191,6 +315,7 @@ int readproc() n = p->next; if (p->argv0) free(p->argv0); if (p->argv1) free(p->argv1); + if (p->statname) free(p->statname); free(p); } plist = NULL; @@ -225,6 +350,9 @@ int readproc() nsyslog(LOG_ERR, "can't get program name from %s\n", path); + if (p->argv0) free(p->argv0); + if (p->argv1) free(p->argv1); + if (p->statname) free(p->statname); free(p); continue; } @@ -248,6 +376,9 @@ int readproc() p->sid = 0; nsyslog(LOG_ERR, "can't read sid from %s\n", path); + if (p->argv0) free(p->argv0); + if (p->argv1) free(p->argv1); + if (p->statname) free(p->statname); free(p); continue; } @@ -256,6 +387,9 @@ int readproc() fclose(fp); } else { /* Process disappeared.. */ + if (p->argv0) free(p->argv0); + if (p->argv1) free(p->argv1); + if (p->statname) free(p->statname); free(p); continue; } @@ -300,13 +434,18 @@ int readproc() } else { /* Process disappeared.. */ + if (p->argv0) free(p->argv0); + if (p->argv1) free(p->argv1); + if (p->statname) free(p->statname); free(p); continue; } /* Try to stat the executable. */ snprintf(path, sizeof(path), "/proc/%s/exe", d->d_name); - if (stat(path, &st) == 0) { + if (check4nfs(path, NULL)) + p->nfs = 1; + if ((p->nfs == 0) && (stat(path, &st) == 0)) { p->dev = st.st_dev; p->ino = st.st_ino; } @@ -374,12 +513,25 @@ PIDQ_HEAD *pidof(char *prog) PIDQ_HEAD *q; struct stat st; char *s; + int nfs = 0; int dostat = 0; int foundone = 0; int ok = 0; + char real[PATH_MAX+1]; /* Try to stat the executable. */ - if (prog[0] == '/' && stat(prog, &st) == 0) dostat++; + if (prog[0] == '/') { + memset(&real[0], 0, sizeof(real)); + + if (check4nfs(prog, real)) + nfs++; /* Binary located on NFS partition. */ + + if (real[0] != '\0') + prog = &real[0]; /* Binary or its symlink located on NFS. */ + + if ((nfs == 0) && (stat(prog, &st) == 0)) + dostat++; /* Binary located on a local file system. */ + } /* Get basename of program. */ if ((s = strrchr(prog, '/')) == NULL) @@ -393,10 +545,30 @@ PIDQ_HEAD *pidof(char *prog) /* First try to find a match based on dev/ino pair. */ if (dostat) { for (p = plist; p; p = p->next) { - if (p->dev == st.st_dev && p->ino == st.st_ino) { - add_pid_to_q(q, p); - foundone++; - } + if (p->nfs) + continue; + if (p->dev != st.st_dev || p->ino != st.st_ino) + continue; + add_pid_to_q(q, p); + foundone++; + } + } + + /* Second try to find a match based on full path name on NFS located binaries */ + if (!foundone && nfs) { + for (p = plist; p; p = p->next) { + char exe [PATH_MAX+1]; + char path[PATH_MAX+1]; + int len; + + snprintf(exe, sizeof(exe), "/proc/%d/exe", p->pid); + if ((len = readlink(exe, path, PATH_MAX)) < 0) + continue; + path[len] = '\0'; + if (strcmp(prog, path) != 0) + continue; + add_pid_to_q(q, p); + foundone++; } } @@ -428,7 +600,7 @@ PIDQ_HEAD *pidof(char *prog) if (ok) add_pid_to_q(q, p); } - return q; + return q; } /* Give usage message and exit. */ @@ -477,6 +649,9 @@ int main_pidof(int argc, char **argv) int first = 1; int i, oind, opt, flags = 0; + /* Which NFS partitions are online? */ + init_nfs(); + for (oind = PIDOF_OMITSZ-1; oind > 0; oind--) opid[oind] = 0; opterr = 0; @@ -561,6 +736,7 @@ int main(int argc, char **argv) PROC *p; int pid, sid = -1; int sig = SIGKILL; + int did_mount; /* Get program name. */ if ((progname = strrchr(argv[0], '/')) == NULL) @@ -583,7 +759,10 @@ int main(int argc, char **argv) } /* First get the /proc filesystem online. */ - mount_proc(); + did_mount = mount_proc(); + + /* Which NFS partitions are online? */ + init_nfs(); /* * Ignoring SIGKILL and SIGSTOP do not make sense, but @@ -608,9 +787,13 @@ int main(int argc, char **argv) /* Now kill all processes except our session. */ sid = (int)getsid(0); pid = (int)getpid(); - for (p = plist; p; p = p->next) - if (p->pid != pid && p->sid != sid && !p->kernel) - kill(p->pid, sig); + for (p = plist; p; p = p->next) { + if (p->pid == 1 || p->pid == pid || p->sid == sid || p->kernel) { + kill(p->pid, SIGCONT); + continue; + } + kill(p->pid, sig); + } /* And let them continue. */ kill(-1, SIGCONT);