Dr. Werner Fink 2010-07-13 16:50:33 +00:00 committed by Git OBS Bridge
parent d57396fe8d
commit 27d2e910a5
21 changed files with 1505 additions and 1424 deletions

269
psmisc-22.12-leaks.patch Normal file
View File

@ -0,0 +1,269 @@
--- src/fuser.c
+++ src/fuser.c 2010-07-13 14:42:02.762926098 +0000
@@ -148,18 +148,12 @@ scan_procs(struct names *names_head, str
{
DIR *topproc_dir;
struct dirent *topproc_dent;
- char *fd_dirpath, *fd_pathname;
struct inode_list *ino_tmp;
struct device_list *dev_tmp;
pid_t pid, my_pid;
uid_t uid;
struct stat *cwd_stat, *exe_stat, *root_stat;
- if ((fd_dirpath = malloc(MAX_PATHNAME)) == NULL)
- return;
- if ((fd_pathname = malloc(MAX_PATHNAME)) == NULL)
- return;
-
if ((topproc_dir = opendir("/proc")) == NULL) {
fprintf(stderr, _("Cannot open /proc directory: %s\n"),
strerror(errno));
@@ -219,6 +213,9 @@ scan_procs(struct names *names_head, str
}
}
}
+ if (root_stat) free(root_stat);
+ if (cwd_stat) free(cwd_stat);
+ if (exe_stat) free(exe_stat);
check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
sockets, netdev);
check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
@@ -237,10 +234,9 @@ add_inode(struct inode_list **ino_list,
{
struct inode_list *ino_tmp, *ino_head;
- ino_head = *ino_list;
-
- if ((ino_tmp = malloc(sizeof(struct inode_list))) == NULL)
+ if ((ino_tmp = (struct inode_list*)malloc(sizeof(struct inode_list))) == NULL)
return;
+ ino_head = *ino_list;
ino_tmp->name = this_name;
ino_tmp->device = device;
ino_tmp->inode = inode;
@@ -254,10 +250,10 @@ add_device(struct device_list **dev_list
struct device_list *dev_tmp, *dev_head;
/*printf("Adding device %s %d\n", this_name->filename, device); */
- dev_head = *dev_list;
- if ((dev_tmp = malloc(sizeof(struct device_list))) == NULL)
+ if ((dev_tmp = (struct device_list*)malloc(sizeof(struct device_list))) == NULL)
return;
+ dev_head = *dev_list;
dev_tmp->name = this_name;
dev_tmp->device = device;
dev_tmp->next = dev_head;
@@ -271,10 +267,9 @@ add_ip_conn(struct ip_connections **ip_l
{
struct ip_connections *ip_tmp, *ip_head;
- ip_head = *ip_list;
-
- if ((ip_tmp = malloc(sizeof(struct ip_connections))) == NULL)
+ if ((ip_tmp = (struct ip_connections*)malloc(sizeof(struct ip_connections))) == NULL)
return;
+ ip_head = *ip_list;
ip_tmp->name = this_name;
ip_tmp->lcl_port = lcl_port;
ip_tmp->rmt_port = rmt_port;
@@ -292,10 +287,9 @@ add_ip6_conn(struct ip6_connections **ip
{
struct ip6_connections *ip_tmp, *ip_head;
- ip_head = *ip_list;
-
- if ((ip_tmp = malloc(sizeof(struct ip6_connections))) == NULL)
+ if ((ip_tmp = (struct ip6_connections*)malloc(sizeof(struct ip6_connections))) == NULL)
return;
+ ip_head = *ip_list;
ip_tmp->name = this_name;
ip_tmp->lcl_port = lcl_port;
ip_tmp->rmt_port = rmt_port;
@@ -326,7 +320,7 @@ add_matched_proc(struct names *name_list
}
}
/* Not found */
- if ((pptr = malloc(sizeof(struct procs))) == NULL) {
+ if ((pptr = (struct procs*)malloc(sizeof(struct procs))) == NULL) {
fprintf(stderr,
_("Cannot allocate memory for matched proc: %s\n"),
strerror(errno));
@@ -339,10 +333,13 @@ add_matched_proc(struct names *name_list
pptr->next = NULL;
/* set command name */
pptr->command = NULL;
+
+ fp = NULL;
+ pathname = NULL;
if ((asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
((fp = fopen(pathname, "r")) != NULL) &&
(fscanf(fp, "%*d (%100[^)]", cmdname) == 1))
- if ((pptr->command = malloc(MAX_CMDNAME + 1)) != NULL) {
+ if ((pptr->command = (char*)malloc(MAX_CMDNAME + 1)) != NULL) {
cmdlen = 0;
for (cptr = cmdname; cmdlen < MAX_CMDNAME && *cptr;
cptr++) {
@@ -359,6 +356,10 @@ add_matched_proc(struct names *name_list
name_list->matched_procs = pptr;
else
last_proc->next = pptr;
+ if (pathname)
+ free(pathname);
+ if (fp)
+ fclose(fp);
}
/* Adds a knfsd etc process */
@@ -680,7 +681,7 @@ find_net_sockets(struct inode_list **ino
}
}
- return;
+ fclose(fp);
}
#ifdef WITH_IPV6
@@ -753,6 +754,7 @@ find_net6_sockets(struct inode_list **in
}
}
}
+ fclose(fp);
}
#endif
@@ -1253,13 +1255,15 @@ static struct stat *get_pidstat(const pi
char pathname[256];
struct stat *st;
- if ((st = malloc(sizeof(struct stat))) == NULL)
+ if ((st = (struct stat*)malloc(sizeof(struct stat))) == NULL)
return NULL;
snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
if (stat(pathname, st) != 0)
- return NULL;
- else
- return st;
+ goto out;
+ return st;
+out:
+ free(st);
+ return NULL;
}
static void
@@ -1267,7 +1271,7 @@ check_dir(const pid_t pid, const char *d
struct inode_list *ino_head, const uid_t uid, const char access,
struct unixsocket_list *sockets, dev_t netdev)
{
- char *dirpath, *filepath;
+ char *dirpath = NULL, *filepath = NULL;
DIR *dirp;
struct dirent *direntry;
struct inode_list *ino_tmp;
@@ -1275,14 +1279,14 @@ check_dir(const pid_t pid, const char *d
struct unixsocket_list *sock_tmp;
struct stat st, lst;
- if ((dirpath = malloc(MAX_PATHNAME)) == NULL)
- return;
- if ((filepath = malloc(MAX_PATHNAME)) == NULL)
- return;
+ if ((dirpath = (char*)malloc(MAX_PATHNAME)) == NULL)
+ goto out;
+ if ((filepath = (char*)malloc(MAX_PATHNAME)) == NULL)
+ goto out;
snprintf(dirpath, MAX_PATHNAME, "/proc/%d/%s", pid, dirname);
if ((dirp = opendir(dirpath)) == NULL)
- return;
+ goto out;
while ((direntry = readdir(dirp)) != NULL) {
if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
continue;
@@ -1341,6 +1345,11 @@ check_dir(const pid_t pid, const char *d
}
} /* while fd_dent */
closedir(dirp);
+out:
+ if (dirpath)
+ free(dirpath);
+ if (filepath)
+ free(filepath);
}
static void
@@ -1400,7 +1409,6 @@ void fill_unix_cache(struct unixsocket_l
{
FILE *fp;
char line[BUFSIZ];
- char *scanned_path;
int scanned_inode;
struct stat st;
struct unixsocket_list *newsocket;
@@ -1411,24 +1419,38 @@ void fill_unix_cache(struct unixsocket_l
return;
}
while (fgets(line, BUFSIZ, fp) != NULL) {
+ char * path;
+ char * scanned_path = NULL;
if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %d %as",
- &scanned_inode, &scanned_path) != 2)
+ &scanned_inode, &scanned_path) != 2) {
+ if (scanned_path)
+ free(scanned_path);
continue;
+ }
+ if (scanned_path == NULL)
+ continue;
+ path = scanned_path;
+ if (*scanned_path == '@')
+ scanned_path++;
if (stat(scanned_path, &st) < 0) {
- free(scanned_path);
+ free(path);
continue;
}
- if ((newsocket =
- malloc(sizeof(struct unixsocket_list))) == NULL)
+ if ((newsocket = (struct unixsocket_list*)
+ malloc(sizeof(struct unixsocket_list))) == NULL) {
+ free(path);
continue;
+ }
newsocket->sun_name = strdup(scanned_path);
newsocket->inode = st.st_ino;
newsocket->dev = st.st_dev;
newsocket->net_inode = scanned_inode;
newsocket->next = *unixsocket_head;
*unixsocket_head = newsocket;
+ free(path);
} /* while */
+ fclose(fp);
}
#ifdef DEBUG
@@ -1567,6 +1589,7 @@ scan_knfsd(struct names *names_head, str
line);
}
}
+ fclose(fp);
}
static void
@@ -1610,6 +1633,7 @@ scan_mounts(struct names *names_head, st
find_mountp);
}
}
+ fclose(fp);
}
static void
@@ -1656,4 +1680,5 @@ scan_swaps(struct names *names_head, str
line);
}
}
+ fclose(fp);
}

View File

@ -0,0 +1,903 @@
--- doc/fuser.1
+++ doc/fuser.1 2010-07-13 11:19:41.000000000 +0000
@@ -88,8 +88,14 @@ List all known signal names.
\fINAME\fR specifies a file on a mounted file system or a block device that
is mounted. All processes accessing files on that file system are listed.
If a directory file is specified, it is automatically changed to
-\fINAME\fR/. to use any file system that might be mounted on that
-directory.
+\fINAME\fR/. To use any file system that might be mounted on that
+directory. Please note that due the required device ID comparision all
+mounted file systems the
+.BR stat (2)
+system call will applied to every file system even on network file system
+(NFS). If the NFS server does not respond or the network is down the
+.BR stat (2)
+may hang forever.
.TP
\fB\-M\f, \fB\-\-ismountpoint\fR
Request will be fulfilled only if \fINAME\fR specifies a mountpoint.
@@ -174,10 +180,13 @@ The \fB\-k\fR option only works on proce
\fBfuser\fR will print an advice, but take no action beyond that.
.SH BUGS
.PP
-fuser \-m /dev/sgX will show (or kill with the \-k flag) all processes, even
+\fBfuser \-m \fI/dev/sgX\fR will show (or kill with the \fB\-k\fR flag) all processes, even
if you don't have that device configured. There may be other devices it
does this for too.
.PP
+\fBfuser \-m \fIname\fR may hang forever if there are NFS file systems mounted
+and one of the NFS servers do not respond or the corresponding network is down.
+.PP
.B fuser
cannot report on any processes that it doesn't have permission to look at
the file descriptor table for. The most common time this problem occurs
--- src/fuser.c
+++ src/fuser.c 2010-07-13 16:28:32.051424747 +0000
@@ -32,9 +32,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pwd.h>
@@ -45,6 +47,7 @@
#include <mntent.h>
#include <signal.h>
#include <getopt.h>
+#include <setjmp.h>
#include "fuser.h"
#include "signals.h"
@@ -67,7 +70,8 @@ static void check_map(const pid_t pid, c
struct device_list *dev_head,
struct inode_list *ino_head, const uid_t uid,
const char access);
-static struct stat *get_pidstat(const pid_t pid, const char *filename);
+static struct stat *get_pidstat(const opt_type opts, const pid_t pid,
+ const char *filename, char *real);
static uid_t getpiduid(const pid_t pid);
static int print_matches(struct names *names_head, const opt_type opts,
const int sig_number);
@@ -79,12 +83,12 @@ static void add_device(struct device_lis
struct names *this_name, dev_t device);
void fill_unix_cache(struct unixsocket_list **unixsocket_head);
static dev_t find_net_dev(void);
-static void scan_procs(struct names *names_head, struct inode_list *ino_head,
- struct device_list *dev_head,
+static void scan_procs(const opt_type opts, struct names *names_head,
+ struct inode_list *ino_head, struct device_list *dev_head,
struct unixsocket_list *sockets, dev_t netdev);
static void scan_knfsd(struct names *names_head, struct inode_list *ino_head,
struct device_list *dev_head);
-static void scan_mounts(struct names *names_head,
+static void scan_mounts(struct names *names_head, struct mount_list *mounts,
struct inode_list *ino_head,
struct device_list *dev_head);
static void scan_swaps(struct names *names_head, struct inode_list *ino_head,
@@ -95,6 +99,13 @@ static void debug_match_lists(struct nam
struct device_list *dev_head);
#endif
+static struct nfs_points *mnts;
+static void clear_mnt(void);
+static int check4nfs(const char * path, char * real);
+
+typedef int (*stat_t)(const char*, struct stat*);
+static int nfssafe(stat_t func, const char *path, struct stat *buf);
+
static void usage(const char *errormsg)
{
if (errormsg != NULL)
@@ -141,8 +152,15 @@ void print_version()
"For more information about these matters, see the files named COPYING.\n"));
}
+static int islocatedon(const char * path, const char * loc)
+{
+ if (!path || *path == '\0')
+ return 0;
+ return (strstr(path, loc) == path);
+}
+
static void
-scan_procs(struct names *names_head, struct inode_list *ino_head,
+scan_procs(const opt_type opts, struct names *names_head, struct inode_list *ino_head,
struct device_list *dev_head, struct unixsocket_list *sockets,
dev_t netdev)
{
@@ -153,6 +171,9 @@ scan_procs(struct names *names_head, str
pid_t pid, my_pid;
uid_t uid;
struct stat *cwd_stat, *exe_stat, *root_stat;
+ char root_real[PATH_MAX+1];
+ char cwd_real[PATH_MAX+1];
+ char exe_real[PATH_MAX+1];
if ((topproc_dir = opendir("/proc")) == NULL) {
fprintf(stderr, _("Cannot open /proc directory: %s\n"),
@@ -169,9 +190,10 @@ scan_procs(struct names *names_head, str
continue;
uid = getpiduid(pid);
- root_stat = get_pidstat(pid, "root");
- cwd_stat = get_pidstat(pid, "cwd");
- exe_stat = get_pidstat(pid, "exe");
+ root_real[0] = cwd_real[0] = exe_real[0] = '\0';
+ root_stat = get_pidstat(opts, pid, "root", root_real);
+ cwd_stat = get_pidstat(opts, pid, "cwd", cwd_real);
+ exe_stat = get_pidstat(opts, pid, "exe", exe_real);
/* Scan the devices */
for (dev_tmp = dev_head; dev_tmp != NULL;
dev_tmp = dev_tmp->next) {
@@ -187,6 +209,17 @@ scan_procs(struct names *names_head, str
&& cwd_stat->st_dev == dev_tmp->device)
add_matched_proc(dev_tmp->name, pid, uid,
ACCESS_CWD);
+ if ((dev_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (islocatedon(&exe_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid,
+ ACCESS_EXE);
+ if (islocatedon(&root_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid,
+ ACCESS_ROOT);
+ if (islocatedon(&cwd_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid,
+ ACCESS_CWD);
}
for (ino_tmp = ino_head; ino_tmp != NULL;
ino_tmp = ino_tmp->next) {
@@ -212,14 +245,27 @@ scan_procs(struct names *names_head, str
uid, ACCESS_CWD);
}
}
+ if ((ino_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (islocatedon(&exe_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid,
+ ACCESS_EXE);
+ if (islocatedon(&root_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid,
+ ACCESS_ROOT);
+ if (islocatedon(&cwd_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid,
+ ACCESS_CWD);
}
if (root_stat) free(root_stat);
if (cwd_stat) free(cwd_stat);
if (exe_stat) free(exe_stat);
+#ifndef __linux__
check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP,
sockets, netdev);
check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP,
sockets, netdev);
+#endif
check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE,
sockets, netdev);
check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
@@ -394,6 +440,23 @@ add_special_proc(struct names *name_list
int parse_file(struct names *this_name, struct inode_list **ino_list)
{
+ char real[PATH_MAX+1] = "";
+
+ real[0] = '\0';
+ if (check4nfs(this_name->filename, real)) {
+ if (this_name->filename)
+ free(this_name->filename);
+ this_name->filename = strdup(real);
+ this_name->name_space |= NAMESPACE_NFS;
+ add_inode(ino_list, this_name, (dev_t)-1, (ino_t)-1);
+ return 0;
+ }
+ if (real[0] != '\0') {
+ if (this_name->filename)
+ free(this_name->filename);
+ this_name->filename = strdup(real);
+ }
+
if (stat(this_name->filename, &(this_name->st)) != 0) {
if (errno == ENOENT)
fprintf(stderr, _("Specified filename %s does not exist.\n"), this_name->filename);
@@ -411,12 +474,12 @@ int parse_file(struct names *this_name,
int
parse_unixsockets(struct names *this_name, struct inode_list **ino_list,
- struct unixsocket_list *sun_head)
+ struct unixsocket_list *sun_head, dev_t net_dev)
{
struct unixsocket_list *sun_tmp;
- dev_t net_dev;
- net_dev = find_net_dev();
+ if (this_name->name_space & NAMESPACE_NFS)
+ return 0;
for (sun_tmp = sun_head; sun_tmp != NULL; sun_tmp = sun_tmp->next) {
if (sun_tmp->dev == this_name->st.st_dev && sun_tmp->inode == this_name->st.st_ino) {
@@ -429,10 +492,14 @@ parse_unixsockets(struct names *this_nam
}
int
-parse_mounts(struct names *this_name, struct device_list **dev_list,
- const char opts)
+parse_mounts(struct names *this_name, struct mount_list *mounts,
+ struct device_list **dev_list)
{
dev_t match_device;
+ struct mount_list *mountptr;
+
+ if (this_name->name_space & NAMESPACE_NFS)
+ goto skip;
if (S_ISBLK(this_name->st.st_mode))
match_device = this_name->st.st_rdev;
@@ -440,6 +507,13 @@ parse_mounts(struct names *this_name, st
match_device = this_name->st.st_dev;
add_device(dev_list, this_name, match_device);
return 0;
+skip:
+ match_device = -1;
+ for (mountptr = mounts ; mountptr != NULL ; mountptr = mountptr->next) {
+ if (strcmp(mountptr->mountpoint, this_name->filename) == 0)
+ add_device(dev_list, this_name, match_device);
+ }
+ return 0;
}
#ifdef WITH_IPV6
@@ -758,34 +832,101 @@ find_net6_sockets(struct inode_list **in
}
#endif
+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;
+}
+
static void
read_proc_mounts(struct mount_list **mnt_list)
{
- FILE *fp;
- char line[BUFSIZ];
- char *find_mountp;
- char *find_space;
- struct mount_list *mnt_tmp;
+ FILE *mntfp;
+ struct mntent *mnt_ptr;
+ struct stat st;
+ const char * mtab;
+
+ if (stat("/proc/version", &st) < 0)
+ mtab = PROC_MOUNTS;
+ else
+ mtab = "/etc/mtab";
- if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
- fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
+ if ( (mntfp = setmntent(mtab,"r")) == NULL) {
+ fprintf(stderr, _("Cannot open %s: %s\n"), mtab,
+ strerror(errno));
return;
}
- while (fgets(line, BUFSIZ, fp) != NULL) {
- if ((find_mountp = strchr(line, ' ')) == NULL)
- continue;
- find_mountp++;
- if ((find_space = strchr(find_mountp, ' ')) == NULL)
- continue;
- *find_space = '\0';
- if ((mnt_tmp = malloc(sizeof(struct mount_list))) == NULL)
+ while ((mnt_ptr = getmntent(mntfp)) != NULL) {
+ struct mount_list *mnt_tmp;
+ if (isnetfs(mnt_ptr->mnt_type)) {
+ /*
+ * Remember all NFS typed partitions, required to make check4nfs() work.
+ */
+ size_t nlen = strlen(mnt_ptr->mnt_dir);
+ struct nfs_points *restrict p;
+ if (posix_memalign((void*)&p, sizeof(void*), alignof(struct nfs_points)+(nlen+1)) != 0)
+ goto out;
+ p->name = ((char*)p)+alignof(struct nfs_points);
+ p->nlen = nlen;
+ p->shadow = (struct shadow_list*)0;
+
+ strcpy(p->name, mnt_ptr->mnt_dir);
+ if (mnts)
+ mnts->prev = p;
+ p->next = mnts;
+ p->prev = (struct nfs_points*)0;
+ mnts = p;
+ }
+ if ((mnt_tmp = (struct mount_list*)malloc(sizeof(struct mount_list))) == NULL)
continue;
- if ((mnt_tmp->mountpoint = strdup(find_mountp)) == NULL)
+ if ((mnt_tmp->mountpoint = strdup(mnt_ptr->mnt_dir)) == NULL)
continue;
mnt_tmp->next = *mnt_list;
*mnt_list = mnt_tmp;
}
- fclose(fp);
+ endmntent(mntfp);
+
+ if (!mnts)
+ return;
+
+ if ((mntfp = setmntent(mtab, "r")) == NULL) {
+ fprintf(stderr, _("Cannot open %s: %s\n"), mtab,
+ strerror(errno));
+ return;
+ }
+
+ while ((mnt_ptr = getmntent(mntfp)) != NULL) {
+ struct nfs_points *p;
+
+ for (p = mnts; p; p = p->next) {
+ struct shadow_list *s;
+ size_t nlen;
+
+ if (strcmp(mnt_ptr->mnt_dir, p->name) == 0)
+ continue;
+ if (strncmp(mnt_ptr->mnt_dir, p->name, p->nlen) != 0)
+ continue;
+
+ nlen = strlen(mnt_ptr->mnt_dir);
+ if (posix_memalign((void*)&s, sizeof(void*), alignof(struct shadow_list)+(nlen+1)) != 0)
+ goto out;
+ s->name = ((char*)s)+alignof(struct shadow_list);
+ s->nlen = nlen;
+
+ strcpy(s->name, mnt_ptr->mnt_dir);
+ if (p->shadow)
+ p->shadow->prev = s;
+ s->next = p->shadow;
+ s->prev = (struct shadow_list*)0;
+ p->shadow = s;
+ }
+ }
+out:
+ endmntent(mntfp);
}
static int
@@ -808,6 +949,150 @@ is_mountpoint(struct mount_list **mnt_li
return 0;
}
+/*
+ * Remove struct nfs_points and its sahdows from memory
+ */
+static void clear_shadow(struct shadow_list *restrict shadow)
+{
+ struct shadow_list *s, *n, *l;
+
+ n = shadow;
+ l = (struct shadow_list*)0;
+ for (s = shadow; n; s = n) {
+ l = s->prev;
+ n = s->next;
+ if (s == shadow) {
+ if (n) n->prev = (struct shadow_list*)0;
+ shadow = n;
+ } else if (l) {
+ if (n) n->prev = l;
+ l->next = n;
+ }
+ free(s);
+ }
+}
+
+static void clear_mnt(void)
+{
+ struct nfs_points *p, *n, *l;
+
+ n = mnts;
+ l = (struct nfs_points*)0;
+ for (p = mnts; n; p = n) {
+ l = p->prev;
+ n = p->next;
+ if (p == mnts) {
+ if (n) n->prev = (struct nfs_points*)0;
+ mnts = n;
+ } else if (l) {
+ if (n) n->prev = l;
+ l->next = n;
+ }
+ if (p->shadow)
+ clear_shadow(p->shadow);
+ free(p);
+ }
+}
+
+/*
+ * Check if path is a shadow of a NFS partition.
+ */
+static int shadow(struct shadow_list *restrict this, const char *restrict name, const size_t nlen)
+{
+ struct shadow_list *s;
+
+ if (!this)
+ goto out;
+ for (s = this; s; s = s->next) {
+ if (nlen < s->nlen)
+ continue;
+ if (name[s->nlen] != '\0' && name[s->nlen] != '/')
+ continue;
+ if (strncmp(name, s->name, s->nlen) == 0)
+ return 1;
+ }
+out:
+ return 0;
+}
+
+/*
+ * Check path is located on a NFS partition.
+ */
+static int check4nfs(const char * path, char * real)
+{
+ char buf[PATH_MAX+1];
+ const char *curr;
+ int deep = MAXSYMLINKS;
+
+ if (!mnts) return 0;
+
+ curr = path;
+ do {
+ const char *prev;
+ int len;
+
+ if ((prev = strdupa(curr)) == NULL)
+ return 0;
+
+ errno = 0;
+ if ((len = readlink(curr, buf, PATH_MAX)) < 0)
+ break;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+
+ if (strncmp(prev, "/proc/", 6) == 0) {
+ curr = &buf[0];
+ break; /* /proc/ provides the real path! */
+ }
+
+ if (len > 10) {
+ char *const ptr = &buf[len - 10];
+ if (strcmp(ptr, " (deleted)") == 0) {
+ *ptr = '\0';
+ curr = &buf[0];
+ break; /* Path is deleted from VFS cache */
+ }
+ }
+
+ 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);
+ struct nfs_points *p;
+ for (p = mnts; p; p = p->next) {
+ if (nlen < p->nlen)
+ continue;
+ if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
+ continue;
+ if (!strncmp(curr, p->name, p->nlen)) {
+ if (shadow(p->shadow, curr, nlen))
+ continue;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
opt_type opts;
@@ -835,6 +1120,7 @@ int main(int argc, char *argv[])
struct option *optr;
char *nsptr;
int skip_argv;
+ size_t len;
struct option options[] = {
{"all", 0, NULL, 'a'},
@@ -931,7 +1217,6 @@ int main(int argc, char *argv[])
break;
case 'M':
opts |= OPT_ISMOUNTPOINT;
- read_proc_mounts(&mounts);
break;
case 'n':
argc_cnt++;
@@ -979,6 +1264,9 @@ int main(int argc, char *argv[])
} /* an option */
/* Not an option, must be a file specification */
+ if (!mounts)
+ read_proc_mounts(&mounts);
+
if ((this_name = malloc(sizeof(struct names))) == NULL)
continue;
this_name->next = NULL;
@@ -1030,11 +1318,24 @@ int main(int argc, char *argv[])
break;
default: /* FILE */
this_name->filename = strdup(current_argv);
+ len = strlen(this_name->filename);
+ if (len > 1 && this_name->filename[len-1] == '/')
+ this_name->filename[len-1] = '\0';
+ if (len > 1 && this_name->filename[0] != '/') {
+ char pwd[MAX_PATHNAME];
+ if (getcwd(pwd, MAX_PATHNAME-1)) {
+ char *new, *old = this_name->filename;
+ if (asprintf(&new, "%s/%s", (strlen(pwd) > 1 ? pwd : ""), old) > 0) {
+ this_name->filename = new;
+ free(old);
+ }
+ }
+ }
if (parse_file(this_name, &match_inodes) == 0) {
- parse_unixsockets(this_name, &match_inodes, unixsockets);
+ parse_unixsockets(this_name, &match_inodes, unixsockets, netdev);
if (opts & OPT_MOUNTS)
- parse_mounts(this_name, &match_devices, opts);
- }
+ parse_mounts(this_name, mounts, &match_devices);
+ }
break;
}
@@ -1080,11 +1381,14 @@ int main(int argc, char *argv[])
#ifdef DEBUG
debug_match_lists(names_head, match_inodes, match_devices);
#endif
- scan_procs(names_head, match_inodes, match_devices, unixsockets,
- netdev);
- scan_knfsd(names_head, match_inodes, match_devices);
- scan_mounts(names_head, match_inodes, match_devices);
- scan_swaps(names_head, match_inodes, match_devices);
+ scan_procs(opts, names_head, match_inodes, match_devices,
+ unixsockets, netdev);
+ if (opts & OPT_VERBOSE) {
+ scan_knfsd(names_head, match_inodes, match_devices);
+ scan_mounts(names_head, mounts, match_inodes, match_devices);
+ scan_swaps(names_head, match_inodes, match_devices);
+ }
+ clear_mnt();
return print_matches(names_head, opts, sig_number);
}
@@ -1250,7 +1554,7 @@ print_matches(struct names *names_head,
}
-static struct stat *get_pidstat(const pid_t pid, const char *filename)
+static struct stat *get_pidstat(const opt_type opts, const pid_t pid, const char *filename, char *real)
{
char pathname[256];
struct stat *st;
@@ -1258,6 +1562,10 @@ static struct stat *get_pidstat(const pi
if ((st = (struct stat*)malloc(sizeof(struct stat))) == NULL)
return NULL;
snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
+ if (check4nfs(pathname, real)) {
+ if ((opts & OPT_MOUNTS) == 0)
+ return NULL;
+ }
if (stat(pathname, st) != 0)
goto out;
return st;
@@ -1309,6 +1617,16 @@ check_dir(const pid_t pid, const char *d
}
for (dev_tmp = dev_head; dev_tmp != NULL;
dev_tmp = dev_tmp->next) {
+ if (dev_tmp->name->name_space & NAMESPACE_NFS) {
+ char buf[PATH_MAX+1];
+ ssize_t len;
+ if ((len = readlink(filepath, buf, PATH_MAX)) < 0)
+ continue;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+ if (islocatedon(buf, dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid,uid, access);
+ continue;
+ }
if (st.st_dev == dev_tmp->device) {
if (access == ACCESS_FILE
&& (lstat(filepath, &lst) == 0)
@@ -1326,6 +1644,16 @@ check_dir(const pid_t pid, const char *d
}
for (ino_tmp = ino_head; ino_tmp != NULL;
ino_tmp = ino_tmp->next) {
+ if (ino_tmp->name->name_space & NAMESPACE_NFS) {
+ char buf[PATH_MAX+1];
+ ssize_t len;
+ if ((len = readlink(filepath, buf, PATH_MAX)) < 0)
+ continue;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+ if (islocatedon(buf, ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid,uid, access);
+ continue;
+ }
if (st.st_dev == ino_tmp->device
&& st.st_ino == ino_tmp->inode) {
if (access == ACCESS_FILE
@@ -1372,18 +1700,41 @@ check_map(const pid_t pid, const char *f
while (fgets(line, BUFSIZ, fp)) {
if (sscanf(line, "%*s %*s %*s %x:%x %lld",
&tmp_maj, &tmp_min, &tmp_inode) == 3) {
+ const char * filepath = strchr(line, '/');
tmp_device = tmp_maj * 256 + tmp_min;
for (dev_tmp = dev_head; dev_tmp != NULL;
- dev_tmp = dev_tmp->next)
+ dev_tmp = dev_tmp->next) {
+ if (dev_tmp->name->name_space & NAMESPACE_NFS) {
+ char *nl;
+ if (!filepath)
+ continue;
+ if ((nl = strchr(filepath, '\n')))
+ nl = '\0';
+ if (islocatedon(filepath, dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid,uid, access);
+ continue;
+ }
if (dev_tmp->device == tmp_device)
add_matched_proc(dev_tmp->name, pid,
uid, access);
+ }
for (ino_tmp = ino_head; ino_tmp != NULL;
- ino_tmp = ino_tmp->next)
+ ino_tmp = ino_tmp->next) {
+ if (ino_tmp->name->name_space & NAMESPACE_NFS) {
+ char *nl;
+ if (!filepath)
+ continue;
+ if ((nl = strchr(filepath, '\n')))
+ nl = '\0';
+ if (islocatedon(filepath, ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid,uid, access);
+ continue;
+ }
if (ino_tmp->device == tmp_device
&& ino_tmp->inode == tmp_inode)
add_matched_proc(ino_tmp->name, pid,
uid, access);
+ }
}
}
fclose(fp);
@@ -1571,7 +1922,7 @@ scan_knfsd(struct names *names_head, str
if ((find_space = strpbrk(line, " \t")) == NULL)
continue;
*find_space = '\0';
- if (stat(line, &st) != 0) {
+ if (nfssafe(stat, line, &st) != 0) {
continue;
}
/* Scan the devices */
@@ -1580,6 +1931,11 @@ scan_knfsd(struct names *names_head, str
if (st.st_dev == dev_tmp->device)
add_special_proc(dev_tmp->name, PTYPE_KNFSD, 0,
line);
+ if ((dev_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (strcmp(line, dev_tmp->name->filename))
+ continue;
+ add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0, line);
}
for (ino_tmp = ino_head; ino_tmp != NULL;
ino_tmp = ino_tmp->next) {
@@ -1587,53 +1943,55 @@ scan_knfsd(struct names *names_head, str
&& st.st_ino == ino_tmp->inode)
add_special_proc(ino_tmp->name, PTYPE_KNFSD, 0,
line);
+ if ((ino_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (strcmp(line, ino_tmp->name->filename))
+ continue;
+ add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0, line);
}
}
fclose(fp);
}
static void
-scan_mounts(struct names *names_head, struct inode_list *ino_head,
- struct device_list *dev_head)
+scan_mounts(struct names *names_head, struct mount_list *mounts,
+ struct inode_list *ino_head, struct device_list *dev_head)
{
struct device_list *dev_tmp;
struct inode_list *ino_tmp;
- FILE *fp;
- char line[BUFSIZ];
- char *find_mountp;
- char *find_space;
+ struct mount_list *mountptr;
struct stat st;
- if ((fp = fopen(PROC_MOUNTS, "r")) == NULL) {
- fprintf(stderr, "Cannot open %s\n", PROC_MOUNTS);
- return;
- }
- while (fgets(line, BUFSIZ, fp) != NULL) {
- if ((find_mountp = strchr(line, ' ')) == NULL)
- continue;
- find_mountp++;
- if ((find_space = strchr(find_mountp, ' ')) == NULL)
+ for (mountptr = mounts ; mountptr != NULL ; mountptr = mountptr->next) {
+ if (nfssafe(stat, mountptr->mountpoint, &st) != 0)
continue;
- *find_space = '\0';
- if (stat(find_mountp, &st) != 0) {
- continue;
- }
/* Scan the devices */
for (dev_tmp = dev_head; dev_tmp != NULL;
dev_tmp = dev_tmp->next) {
if (st.st_dev == dev_tmp->device)
add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0,
- find_mountp);
+ mountptr->mountpoint);
+ if ((dev_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (strcmp(mountptr->mountpoint, dev_tmp->name->filename))
+ continue;
+ add_special_proc(dev_tmp->name, PTYPE_MOUNT, 0,
+ mountptr->mountpoint);
}
for (ino_tmp = ino_head; ino_tmp != NULL;
ino_tmp = ino_tmp->next) {
if (st.st_dev == ino_tmp->device
&& st.st_ino == ino_tmp->inode)
add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0,
- find_mountp);
+ mountptr->mountpoint);
+ if ((ino_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (strcmp(mountptr->mountpoint, ino_tmp->name->filename))
+ continue;
+ add_special_proc(ino_tmp->name, PTYPE_MOUNT, 0,
+ mountptr->mountpoint);
}
}
- fclose(fp);
}
static void
@@ -1682,3 +2040,59 @@ scan_swaps(struct names *names_head, str
}
fclose(fp);
}
+
+static sigjmp_buf jenv;
+static int timeout = 5;
+static void
+sigalarm(int sig)
+{
+ if (sig == SIGALRM)
+ siglongjmp(jenv, 1);
+}
+static int
+nfssafe(stat_t func, const char *path, struct stat *buf)
+{
+ pid_t pid = 0;
+ int ret = 0, pipes[4];
+
+ 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)
+ write(pipes[1], buf, sizeof(struct stat));
+ 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;
+ timeout = 1;
+ goto err;
+ }
+ (void) signal(SIGALRM, sigalarm);
+ (void) alarm(timeout);
+ if (read(pipes[0], buf, sizeof(struct stat)) == 0) {
+ errno = EFAULT;
+ ret = -1;
+ }
+ (void) alarm(0);
+ (void) signal(SIGALRM, SIG_DFL);
+ close(pipes[0]);
+ break;
+ }
+ return ret;
+err:
+ return -1;
+}
+
--- src/fuser.h
+++ src/fuser.h 2010-07-13 12:53:15.000000000 +0000
@@ -66,6 +66,11 @@ struct inode_list {
struct inode_list *next;
};
+struct mountdev_list {
+ char *dir;
+ struct mountdev_list *next;
+};
+
struct device_list {
struct names *name;
dev_t device;
@@ -85,9 +90,33 @@ struct mount_list {
struct mount_list *next;
};
+struct shadow_list
+{
+ struct shadow_list *next;
+ struct shadow_list *prev;
+ size_t nlen;
+ char * name;
+};
+
+struct nfs_points {
+ struct nfs_points *next, *prev;
+ struct shadow_list *shadow;
+ size_t nlen;
+ char * name;
+};
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef restrict
+# define restrict __restrict__
+# endif
+#endif
+#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+
+
#define NAMESPACE_FILE 0
#define NAMESPACE_TCP 1
#define NAMESPACE_UDP 2
+#define NAMESPACE_NFS 4
#define MAX_PATHNAME 200
#define MAX_CMDNAME 16

74
psmisc-22.12-pstree.patch Normal file
View File

@ -0,0 +1,74 @@
--- src/pstree.c
+++ src/pstree.c 2010-07-13 10:27:54.139239142 +0000
@@ -61,6 +61,7 @@ extern const char *__progname;
#define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
#define VT_BEG "\033(0\017" /* use graphic chars */
+#define VT_LEN 4
#define VT_END "\033(B" /* back to normal char set */
#define VT_V "x" /* see UTF definitions above */
#define VT_VR "t"
@@ -230,6 +231,27 @@ static void out_scontext(security_contex
}
#endif /*WITH_SELINUX */
+/*
+ * Only affects vt100 line drawing mode: Do not count the strlen of
+ * VT_BEG to prevent doing end-of-line way too early:
+ */
+static void
+out_sym (const char *str)
+{
+ int seq = 0;
+ if (sym == &sym_vt100 && *str == '\033') {
+ seq = 1;
+ if (cur_x <= output_width || !trunc)
+ cur_x -= VT_LEN;
+ }
+ out_string(str);
+ if (seq) {
+ str = VT_END;
+ while (*str)
+ putchar (*str++);
+ }
+}
+
static void out_newline(void)
{
@@ -426,11 +448,12 @@ dump_tree(PROC * current, int level, int
for (lvl = 0; lvl < level; lvl++) {
for (i = width[lvl] + 1; i; i--)
out_char(' ');
- out_string(lvl ==
- level -
- 1 ? last ? sym->last_2 : sym->branch_2 : more[lvl +
- 1] ?
- sym->vert_2 : sym->empty_2);
+ /*
+ * Replace all three symbol-drawing calls with calls to out_sym()
+ * to handle VT100 line drawing sequences if VT100 mode is active:
+ */
+ out_sym(lvl == level - 1 ? last ? sym->last_2 : sym->branch_2 :
+ more[lvl + 1] ? sym->vert_2 : sym->empty_2);
}
if (rep < 2)
add = 0;
@@ -531,7 +554,7 @@ dump_tree(PROC * current, int level, int
}
width[level] = comm_len + cur_x - offset + add;
if (cur_x >= output_width && trunc) {
- out_string(sym->first_3);
+ out_sym(sym->first_3);
out_string("+");
out_newline();
return;
@@ -553,7 +576,7 @@ dump_tree(PROC * current, int level, int
}
}
if (first) {
- out_string(next ? sym->first_3 : sym->single_3);
+ out_sym(next ? sym->first_3 : sym->single_3);
first = 0;
}
dump_tree(walk->child, level + 1, count + 1,

View File

@ -0,0 +1,11 @@
--- src/pstree.c
+++ src/pstree.c 2010-07-13 10:18:31.454925471 +0000
@@ -69,7 +69,7 @@ extern const char *__progname;
#define VT_HD "w"
typedef struct _proc {
- char comm[COMM_LEN + 1];
+ char comm[COMM_LEN + 2 + 1]; /* add another 2 for thread brackets */
char **argv; /* only used : argv[0] is 1st arg; undef if argc < 1 */
int argc; /* with -a : number of arguments, -1 if swapped */
pid_t pid;

View File

@ -0,0 +1,11 @@
--- src/pstree.c
+++ src/pstree.c 2010-07-13 10:14:50.978925622 +0000
@@ -868,7 +868,7 @@ int main(int argc, char **argv)
} else if (isatty(1) && (termname = getenv("TERM")) &&
(strlen(termname) > 0) &&
(setupterm(NULL, 1 /* stdout */ , NULL) == OK) &&
- (tigetstr("acsc") > 0)) {
+ ((int)tigetstr("acsc") > 0)) {
/*
* Failing that, if TERM is defined, a non-null value, and the terminal
* has the VT100 graphics charset, use it.

View File

@ -0,0 +1,129 @@
--- doc/fuser.1
+++ doc/fuser.1 2010-07-13 13:19:57.000000000 +0000
@@ -12,6 +12,7 @@ fuser \- identify processes using files
.RB [ \-k
.RB [ \-i ]
.RB [ \-M ]
+.RB [ \-w ]
.RB [ \- \fISIGNAL
] ]
.IR name " ..."
@@ -102,6 +103,10 @@ Request will be fulfilled only if \fINAM
This is an invaluable seatbelt which prevents you from killing the machine
if \fINAME\fR happens to not be a filesystem.
.TP
+\fB\-w\fP
+Kill only processes which have write access. This option is
+silently ignored if \fB\-k\fP is not present too.
+.TP
\fB\-n \fISPACE\fR, \fB\-\-namespace\fR \fISPACE\fR
Select a different name space. The name spaces \fBfile\fR (file names, the
default), \fBudp\fR (local UDP ports), and \fBtcp\fR (local TCP ports) are
--- src/fuser.c
+++ src/fuser.c 2010-07-13 13:25:44.000000000 +0000
@@ -75,7 +75,7 @@ static struct stat *get_pidstat(const op
static uid_t getpiduid(const pid_t pid);
static int print_matches(struct names *names_head, const opt_type opts,
const int sig_number);
-static void kill_matched_proc(struct procs *pptr, const opt_type opts,
+static int kill_matched_proc(struct procs *pptr, const opt_type opts,
const int sig_number);
/*int parse_mount(struct names *this_name, struct device_list **dev_list);*/
@@ -127,6 +127,7 @@ static void usage(const char *errormsg)
" -SIGNAL send this signal instead of SIGKILL\n"
" -u,--user display user IDs\n"
" -v,--verbose verbose output\n"
+ " -w,--writeonly kill only processes with write access\n"
" -V,--version display version information\n"));
#ifdef WITH_IPV6
fprintf(stderr, _(
@@ -1133,6 +1134,7 @@ int main(int argc, char *argv[])
{"silent", 0, NULL, 's'},
{"user", 0, NULL, 'u'},
{"verbose", 0, NULL, 'v'},
+ {"writeonly", 0, NULL, 'w'},
{"version", 0, NULL, 'V'},
#ifdef WITH_IPV6
{"ipv4", 0, NULL, '4'},
@@ -1244,6 +1246,9 @@ int main(int argc, char *argv[])
case 'v':
opts |= OPT_VERBOSE;
break;
+ case 'w':
+ opts |= OPT_WRITE;
+ break;
case 'V':
print_version();
return 0;
@@ -1406,6 +1411,7 @@ print_matches(struct names *names_head,
int len = 0;
struct passwd *pwent = NULL;
int have_match = 0;
+ int have_kill = 0;
int name_has_procs;
for (nptr = names_head; nptr != NULL; nptr = nptr->next) {
@@ -1546,8 +1552,8 @@ print_matches(struct names *names_head,
}
} /* be silent */
if (opts & OPT_KILL)
- kill_matched_proc(nptr->matched_procs, opts,
- sig_number);
+ have_kill = kill_matched_proc(nptr->matched_procs,
+ opts, sig_number);
} /* next name */
return (have_match == 1 ? 0 : 1);
@@ -1857,12 +1863,13 @@ static int ask(const pid_t pid)
} /* while */
}
-static void
+static int
kill_matched_proc(struct procs *proc_head, const opt_type opts,
const int sig_number)
{
struct procs *pptr;
pid_t mypid;
+ int ret = 0;
mypid = getpid();
@@ -1871,13 +1878,18 @@ kill_matched_proc(struct procs *proc_hea
continue; /* dont kill myself */
if ( pptr->proc_type != PTYPE_NORMAL )
continue;
+ if ((opts & OPT_WRITE) && ((pptr->access & ACCESS_FILEWR) == 0))
+ continue;
if ((opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
continue;
if ( kill(pptr->pid, sig_number) < 0) {
fprintf(stderr, _("Could not kill process %d: %s\n"),
pptr->pid, strerror(errno));
+ continue;
}
+ ret = 1;
}
+ return ret;
}
static dev_t find_net_dev(void)
--- src/fuser.h
+++ src/fuser.h 2010-07-13 13:26:15.000000000 +0000
@@ -1,6 +1,6 @@
/* Option Flags */
-typedef unsigned char opt_type;
+typedef unsigned short opt_type;
#define OPT_VERBOSE 1
#define OPT_ALLFILES 2
@@ -10,6 +10,7 @@ typedef unsigned char opt_type;
#define OPT_SILENT 32
#define OPT_USER 64
#define OPT_ISMOUNTPOINT 128
+#define OPT_WRITE 256
struct procs {
pid_t pid;

49
psmisc-22.12.dif Normal file
View File

@ -0,0 +1,49 @@
--- configure.ac
+++ configure.ac 2010-07-13 13:54:30.000000000 +0000
@@ -66,7 +66,8 @@ AC_CHECK_MEMBERS([struct user_regs_struc
struct user_regs_struct.rdi,
struct user_regs_struct.rsi,
struct user_regs_struct.rdx], [],[],
- [#include <sys/user.h>])
+ [#include <sys/types.h>
+ #include <sys/user.h>])
AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3,
struct pt_regs.gpr], [],[], [#include <linux/ptrace.h>])
AC_CHECK_MEMBERS([struct pt_regs.uregs],[],[], [#include <asm/ptrace.h>])
--- src/fuser.c
+++ src/fuser.c 2010-07-13 15:01:58.000000000 +0000
@@ -1120,7 +1120,8 @@ int main(int argc, char *argv[])
char option_buf[3];
struct option *optr;
char *nsptr;
- int skip_argv;
+ int skip_argv;
+ int seen_file;
size_t len;
struct option options[] = {
@@ -1160,6 +1161,7 @@ int main(int argc, char *argv[])
netdev = find_net_dev();
fill_unix_cache(&unixsockets);
+ seen_file = 0;
for (argc_cnt = 1; argc_cnt < argc; argc_cnt++) {
current_argv = argv[argc_cnt];
if (current_argv[0] == '-') { /* its an option */
@@ -1291,6 +1293,7 @@ int main(int argc, char *argv[])
}
}
this_name->matched_procs = NULL;
+ seen_file = 1;
if (opts & (OPT_MOUNTS|OPT_ISMOUNTPOINT)
&& this_name->name_space != NAMESPACE_FILE)
usage(_
@@ -1350,7 +1353,7 @@ int main(int argc, char *argv[])
names_tail->next = this_name;
names_tail = this_name;
} /* for across the argvs */
- if (names_head == NULL)
+ if (names_head == NULL && !seen_file)
usage(_("No process specification given"));
if (opts & OPT_SILENT) {

3
psmisc-22.12.tar.bz2 Normal file
View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a496b4e684dc5cd5ed28ae296b071701d39845e0a799396dbc005f2736340b1d
size 298393

View File

@ -1,18 +0,0 @@
--- src/fuser.c
+++ src/fuser.c 2008-09-01 15:03:05.000000000 +0200
@@ -1404,6 +1404,7 @@ void fill_unix_cache(struct unixsocket_l
*unixsocket_head = newsocket;
} /* while */
+ fclose(fp);
}
static inline int isnetfs(const char * type)
@@ -1650,6 +1651,7 @@ static void scan_knfsd(struct names *nam
}
}
+ fclose(fp);
}
#endif /* NFSCHECKS */

View File

@ -1,36 +0,0 @@
--- src/fuser.c
+++ src/fuser.c 2008-05-16 14:58:07.906452331 +0200
@@ -1310,12 +1310,21 @@ void fill_unix_cache(struct unixsocket_l
return;
}
while (fgets(line, BUFSIZ, fp) != NULL) {
+ char * path;
+ scanned_path = (char*)0;
if (sscanf(line, "%*x: %*x %*x %*x %*x %*d %d %as",
- &scanned_inode,
- &scanned_path) != 2)
+ &scanned_inode, &scanned_path) != 2) {
+ if (scanned_path)
+ free(scanned_path);
continue;
+ }
+ if (scanned_path == (char*)0)
+ continue;
+ path = scanned_path;
+ if (*scanned_path == '@')
+ scanned_path++;
if (stat(scanned_path, &st) < 0) {
- free(scanned_path);
+ free(path);
continue;
}
if ( (newsocket = malloc(sizeof(struct unixsocket_list))) == NULL)
@@ -1323,7 +1332,7 @@ void fill_unix_cache(struct unixsocket_l
newsocket->sun_name = strdup(scanned_path);
newsocket->inode = st.st_ino;
newsocket->dev = st.st_dev;
- newsocket->net_inode = scanned_inode;
+ newsocket->net_inode = scanned_inode;
newsocket->next = *unixsocket_head;
*unixsocket_head = newsocket;
} /* while */

View File

@ -1,11 +0,0 @@
--- src/pstree.c
+++ src/pstree.c 2008-10-09 16:24:23.000000000 +0200
@@ -912,7 +912,7 @@ main (int argc, char **argv)
} else if (isatty (1) && (termname = getenv ("TERM")) && \
(strlen (termname) > 0) && \
(setupterm (NULL, 1 /* stdout */, NULL) == OK) && \
- (tigetstr ("acsc") > 0)) {
+ ((int)tigetstr ("acsc") > 0)) {
/*
* Failing that, if TERM is defined, a non-null value, and the terminal
* has the VT100 graphics charset, use it.

View File

@ -1,241 +0,0 @@
--- src/fuser.c
+++ src/fuser.c 2009-08-10 11:30:01.674401417 +0200
@@ -225,6 +225,9 @@ static void scan_procs(const opt_type op
if (islocatedon(&cwd_real[0], ino_tmp->name->filename))
add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
}
+ if (root_stat) free(root_stat);
+ if (cwd_stat) free(cwd_stat);
+ if (exe_stat) free(exe_stat);
#ifndef __linux__
check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP, sockets, netdev);
check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP, sockets, netdev);
@@ -239,10 +242,9 @@ static void add_inode(struct inode_list
{
struct inode_list *ino_tmp, *ino_head;
- ino_head = *ino_list;
-
- if ( (ino_tmp = malloc(sizeof(struct inode_list))) == NULL)
+ if ( (ino_tmp = (struct inode_list*)malloc(sizeof(struct inode_list))) == NULL)
return;
+ ino_head = *ino_list;
ino_tmp->name = this_name;
ino_tmp->device = device;
ino_tmp->inode = inode;
@@ -250,15 +252,15 @@ static void add_inode(struct inode_list
*ino_list = ino_tmp;
}
-static void add_device(struct device_list **dev_list, struct names *this_name, dev_t device)
+static void add_device(struct device_list **restrict dev_list, struct names *this_name, dev_t device)
{
struct device_list *dev_tmp, *dev_head;
/*printf("Adding device %s %d\n", this_name->filename, device);*/
- dev_head = *dev_list;
- if ( (dev_tmp = malloc(sizeof(struct device_list))) == NULL)
+ if ( (dev_tmp = (struct device_list*)malloc(sizeof(struct device_list))) == NULL)
return;
+ dev_head = *dev_list;
dev_tmp->name = this_name;
dev_tmp->device = device;
dev_tmp->next = dev_head;
@@ -269,16 +271,14 @@ static void add_ip_conn(struct ip_connec
{
struct ip_connections *ip_tmp, *ip_head;
- ip_head = *ip_list;
-
if ( (ip_tmp = malloc(sizeof(struct ip_connections))) == NULL)
return;
+ ip_head = *ip_list;
ip_tmp->name = this_name;
ip_tmp->lcl_port = lcl_port;
ip_tmp->rmt_port = rmt_port;
ip_tmp->rmt_address.s_addr = rmt_address;
ip_tmp->next = ip_head;
-
*ip_list = ip_tmp;
}
@@ -287,10 +287,9 @@ static void add_ip6_conn(struct ip6_conn
{
struct ip6_connections *ip_tmp, *ip_head;
- ip_head = *ip_list;
-
if ( (ip_tmp = malloc(sizeof(struct ip6_connections))) == NULL)
return;
+ ip_head = *ip_list;
ip_tmp->name = this_name;
ip_tmp->lcl_port = lcl_port;
ip_tmp->rmt_port = rmt_port;
@@ -319,7 +318,7 @@ static void add_matched_proc(struct name
}
}
/* Not found */
- if ( (pptr = malloc(sizeof (struct procs))) == NULL) {
+ if ( (pptr = (struct procs*)malloc(sizeof (struct procs))) == NULL) {
fprintf(stderr,_("Cannot allocate memory for matched proc: %s\n"), strerror(errno));
return;
}
@@ -329,10 +328,13 @@ static void add_matched_proc(struct name
pptr->next = NULL;
/* set command name */
pptr->command = NULL;
+
+ fp = NULL;
+ pathname = NULL;
if ( (asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
( (fp = fopen(pathname, "r")) != NULL) &&
( fscanf(fp, "%*d (%100[^)]", cmdname) == 1))
- if ( (pptr->command = malloc(MAX_CMDNAME+1)) != NULL) {
+ if ( (pptr->command = (char*)malloc(MAX_CMDNAME+1)) != NULL) {
cmdlen = 0;
for (cptr = cmdname; cmdlen < MAX_CMDNAME && *cptr ; cptr++) {
if (isprint(*cptr))
@@ -346,6 +348,10 @@ static void add_matched_proc(struct name
name_list->matched_procs = pptr;
else
last_proc->next = pptr;
+ if (pathname)
+ free(pathname);
+ if (fp)
+ fclose(fp);
}
int parse_mount(struct names *this_name, struct device_list **dev_list)
@@ -372,16 +378,16 @@ int parse_file(struct names *this_name,
real[0] = '\0';
if (check4nfs(this_name->filename, real)) {
- if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0) {
+ if (this_name->filename)
free(this_name->filename);
- this_name->filename = strdup(real);
- this_name->name_space |= NAMESPACE_NFS;
- add_inode(ino_list, this_name, (dev_t)-1, (ino_t)-1);
- return 0;
- }
+ this_name->filename = strdup(real);
+ this_name->name_space |= NAMESPACE_NFS;
+ add_inode(ino_list, this_name, (dev_t)-1, (ino_t)-1);
+ return 0;
}
if (real[0] != '\0') {
- free(this_name->filename);
+ if (this_name->filename)
+ free(this_name->filename);
this_name->filename = strdup(real);
}
@@ -662,7 +668,7 @@ void find_net_sockets(struct inode_list
}
- return ;
+ fclose(fp);
}
#ifdef WITH_IPV6
@@ -725,6 +731,7 @@ void find_net6_sockets(struct inode_list
}
}
}
+ fclose(fp);
}
#endif
@@ -1218,23 +1225,25 @@ static struct stat *get_pidstat(const op
char pathname[256];
struct stat *st;
- if ( (st = malloc(sizeof(struct stat))) == NULL)
+ if ( (st = (struct stat*)malloc(sizeof(struct stat))) == NULL)
return NULL;
snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
if (check4nfs(pathname, real)) {
if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0)
- return NULL;
+ goto out;
}
if (stat(pathname, st) != 0)
- return NULL;
- else
- return st;
+ goto out;
+ return st;
+out:
+ free(st);
+ return NULL;
}
static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access,
struct unixsocket_list *sockets, dev_t netdev)
{
- char *dirpath, *filepath;
+ char *dirpath = NULL, *filepath = NULL;
DIR *dirp;
struct dirent *direntry;
struct inode_list *ino_tmp;
@@ -1243,13 +1252,13 @@ static void check_dir(const pid_t pid, c
struct stat st, lst;
if ( (dirpath = malloc(MAX_PATHNAME)) == NULL)
- return;
+ goto out;
if ( (filepath = malloc(MAX_PATHNAME)) == NULL)
- return;
+ goto out;
snprintf(dirpath, MAX_PATHNAME, "/proc/%d/%s", pid, dirname);
if ( (dirp = opendir(dirpath)) == NULL)
- return;
+ goto out;
while ( (direntry = readdir(dirp)) != NULL) {
if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
continue;
@@ -1293,8 +1302,11 @@ static void check_dir(const pid_t pid, c
}
} /* while fd_dent */
closedir(dirp);
- free(dirpath);
- free(filepath);
+out:
+ if (dirpath)
+ free(dirpath);
+ if (filepath)
+ free(filepath);
}
static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
@@ -1349,7 +1361,7 @@ void add_mount_device(struct mountdev_li
struct mountdev_list *newmount;
/*printf("Adding mount Path: %s Dir:%s dev:%0x\n",dir, fsname, device);*/
- if ( (newmount = malloc(sizeof(struct mountdev_list))) == NULL)
+ if ( (newmount = (struct mountdev_list*)malloc(sizeof(struct mountdev_list))) == NULL)
return;
newmount->fsname = strdup(fsname);
newmount->dir = strdup(dir);
@@ -1394,14 +1406,17 @@ void fill_unix_cache(struct unixsocket_l
free(path);
continue;
}
- if ( (newsocket = malloc(sizeof(struct unixsocket_list))) == NULL)
+ if ( (newsocket = (struct unixsocket_list*)malloc(sizeof(struct unixsocket_list))) == NULL) {
+ free(path);
continue;
+ }
newsocket->sun_name = strdup(scanned_path);
newsocket->inode = st.st_ino;
newsocket->dev = st.st_dev;
newsocket->net_inode = scanned_inode;
newsocket->next = *unixsocket_head;
*unixsocket_head = newsocket;
+ free(path);
} /* while */
fclose(fp);

View File

@ -1,796 +0,0 @@
--- doc/fuser.1
+++ doc/fuser.1 2008-05-16 15:18:59.000000000 +0200
@@ -80,8 +80,14 @@ List all known signal names.
\fIname\fP specifies a file on a mounted file system or a block device that
is mounted. All processes accessing files on that file system are listed.
If a directory file is specified, it is automatically changed to
-\fIname\fP/. to use any file system that might be mounted on that
-directory.
+\fIname\fP/. To use any file system that might be mounted on that
+directory. Please note that due the required device ID comparision all
+mounted file systems the
+.BR stat (2)
+system call will applied to every file system even on network file system
+(NFS). If the NFS server does not respond or the network is down the
+.BR stat (2)
+may hang forever.
.IP \fB\-n\ \fIspace\fP
Select a different name space. The name spaces \fBfile\fP (file names, the
default), \fBudp\fP (local UDP ports), and \fBtcp\fP (local TCP ports) are
@@ -152,10 +158,13 @@ The \fB\-k\fP option only works on proce
\fBfuser\fP will print an advice, but take no action beyond that.
.SH BUGS
.PP
-fuser \-m /dev/sgX will show (or kill with the \-k flag) all processes, even
+\fBfuser \-m \fI/dev/sgX\fR will show (or kill with the \fB\-k\fR flag) all processes, even
if you don't have that device configured. There may be other devices it
does this for too.
.PP
+\fBfuser \-m \fIname\fR may hang forever if there are NFS file systems mounted
+and one of the NFS servers do not respond or the corresponding network is down.
+.PP
.B fuser
cannot report on any processes that it doesn't have permission to look at
the file descriptor table for. The most common time this problem occurs
--- src/fuser.c
+++ src/fuser.c 2009-10-12 17:14:23.228525394 +0200
@@ -32,9 +32,11 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/wait.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pwd.h>
@@ -45,6 +47,7 @@
#include <mntent.h>
#include <signal.h>
#include <getopt.h>
+#include <setjmp.h>
#include "fuser.h"
#include "signals.h"
@@ -63,7 +66,7 @@ static void add_matched_proc(struct name
static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access,
struct unixsocket_list *sockets, dev_t netdev);
static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access);
-static struct stat *get_pidstat(const pid_t pid, const char *filename);
+static struct stat *get_pidstat(const opt_type opts, const pid_t pid, const char *filename, char *real);
static uid_t getpiduid(const pid_t pid);
static int print_matches(struct names *names_head, const opt_type opts, const int sig_number);
static void kill_matched_proc(struct procs *pptr, const opt_type opts, const int sig_number);
@@ -73,13 +76,20 @@ static void add_device(struct device_lis
void scan_mount_devices(const opt_type opts, struct mountdev_list **mount_devices);
void fill_unix_cache(struct unixsocket_list **unixsocket_head);
static dev_t find_net_dev(void);
-static void scan_procs(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head, struct unixsocket_list *sockets, dev_t netdev);
+static void scan_procs(const opt_type opts, struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head, struct unixsocket_list *sockets, dev_t netdev);
#ifdef NFS_CHECKS
static void scan_knfsd(struct names *names_head, struct device_list *dev_head);
#endif /* NFS_CHECKS */
#ifdef DEBUG
static void debug_match_lists(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head);
#endif
+static struct nfs_points *mnts;
+static void clear_mnt(void);
+static int check4nfs(const char * path, char * real);
+
+typedef int (*stat_t)(const char*, struct stat*);
+static int nfssafe(stat_t func, const char *path, struct stat *buf);
+
static void usage (const char *errormsg)
{
@@ -92,7 +102,7 @@ static void usage (const char *errormsg)
" fuser -V\n"
"Show which processes use the named files, sockets, or filesystems.\n\n"
" -a display unused files too\n"
- " -c Same as \-m (for POSIX compatibility)\n"
+ " -c Same as -m (for POSIX compatibility)\n"
" -f silently ignored (for POSIX compatibility)\n"
" -i ask before killing (ignored without -k)\n"
" -k kill processes accessing the named file\n"
@@ -127,7 +137,14 @@ void print_version()
"For more information about these matters, see the files named COPYING.\n"));
}
-static void scan_procs(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head, struct unixsocket_list *sockets, dev_t netdev)
+static int islocatedon(const char * path, const char * loc)
+{
+ if (!path || *path == '\0')
+ return 0;
+ return (strstr(path, loc) == path);
+}
+
+static void scan_procs(const opt_type opts, struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head, struct unixsocket_list *sockets, dev_t netdev)
{
DIR *topproc_dir;
struct dirent *topproc_dent;
@@ -137,6 +154,9 @@ static void scan_procs(struct names *nam
pid_t pid, my_pid;
uid_t uid;
struct stat *cwd_stat, *exe_stat, *root_stat;
+ char root_real[PATH_MAX+1];
+ char cwd_real[PATH_MAX+1];
+ char exe_real[PATH_MAX+1];
if ( (fd_dirpath = malloc(MAX_PATHNAME)) == NULL)
return;
@@ -157,9 +177,10 @@ static void scan_procs(struct names *nam
continue;
uid = getpiduid(pid);
- root_stat = get_pidstat(pid, "root");
- cwd_stat = get_pidstat(pid, "cwd");
- exe_stat = get_pidstat(pid, "exe");
+ root_real[0] = cwd_real[0] = exe_real[0] = '\0';
+ root_stat = get_pidstat(opts, pid, "root", root_real);
+ cwd_stat = get_pidstat(opts, pid, "cwd", cwd_real);
+ exe_stat = get_pidstat(opts, pid, "exe", exe_real);
/* Scan the devices */
for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
if (exe_stat != NULL && exe_stat->st_dev == dev_tmp->device)
@@ -168,6 +189,14 @@ static void scan_procs(struct names *nam
add_matched_proc(dev_tmp->name, pid, uid, ACCESS_ROOT);
if (cwd_stat != NULL && cwd_stat->st_dev == dev_tmp->device)
add_matched_proc(dev_tmp->name, pid, uid, ACCESS_CWD);
+ if ((dev_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (islocatedon(&exe_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid, ACCESS_EXE);
+ if (islocatedon(&root_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid, ACCESS_ROOT);
+ if (islocatedon(&cwd_real[0], dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid, uid, ACCESS_CWD);
}
for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
if (exe_stat != NULL) {
@@ -186,9 +215,19 @@ static void scan_procs(struct names *nam
add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
}
}
+ if ((ino_tmp->name->name_space & NAMESPACE_NFS) == 0)
+ continue;
+ if (islocatedon(&exe_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid, ACCESS_EXE);
+ if (islocatedon(&root_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid, ACCESS_ROOT);
+ if (islocatedon(&cwd_real[0], ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
}
+#ifndef __linux__
check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP, sockets, netdev);
check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP, sockets, netdev);
+#endif
check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE, sockets, netdev);
check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
@@ -325,10 +364,26 @@ int parse_mount(struct names *this_name,
return 0;
}
-int parse_file(struct names *this_name, struct inode_list **ino_list)
+int parse_file(struct names *this_name, struct inode_list **ino_list, const opt_type opts)
{
+ char real[PATH_MAX+1] = "";
struct stat st;
+ real[0] = '\0';
+ if (check4nfs(this_name->filename, real)) {
+ if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0) {
+ free(this_name->filename);
+ this_name->filename = strdup(real);
+ this_name->name_space |= NAMESPACE_NFS;
+ add_inode(ino_list, this_name, (dev_t)-1, (ino_t)-1);
+ return 0;
+ }
+ }
+ if (real[0] != '\0') {
+ free(this_name->filename);
+ this_name->filename = strdup(real);
+ }
+
if (stat(this_name->filename, &st) != 0) {
fprintf(stderr,_("Cannot stat %s: %s\n"), this_name->filename,
strerror(errno));
@@ -342,34 +397,44 @@ int parse_file(struct names *this_name,
return 0;
}
-int parse_unixsockets(struct names *this_name, struct inode_list **ino_list, struct unixsocket_list *sun_head)
+int parse_unixsockets(struct names *this_name, struct inode_list **ino_list, struct unixsocket_list *sun_head, dev_t net_dev, const opt_type opts)
{
struct unixsocket_list *sun_tmp;
struct stat st;
- dev_t net_dev;
-
+
+ if (check4nfs(this_name->filename, NULL)) {
+ this_name->name_space |= NAMESPACE_NFS;
+ return 0;
+ }
+
if (stat(this_name->filename, &st) != 0) {
fprintf(stderr,_("Cannot stat %s: %s\n"), this_name->filename,
strerror(errno));
return -1;
}
- net_dev = find_net_dev();
for (sun_tmp = sun_head; sun_tmp != NULL ; sun_tmp = sun_tmp->next)
{
- if (sun_tmp->dev == st.st_dev && sun_tmp->inode == st.st_ino) {
+ if (sun_tmp->dev == st.st_dev && sun_tmp->inode == st.st_ino) {
add_inode(ino_list, this_name, net_dev, sun_tmp->net_inode);
- return 0;
+ return 0;
}
}
return 0;
}
-int parse_mounts(struct names *this_name, struct mountdev_list *mounts, struct device_list **dev_list, const char opts)
+int parse_mounts(struct names *this_name, struct mountdev_list *mounts, struct device_list **dev_list, const opt_type opts)
{
struct stat st;
struct mountdev_list *mountptr;
dev_t match_device;
+ char real[PATH_MAX+1] = "";
+
+ real[0] = '\0';
+ if (check4nfs(this_name->filename, real)) {
+ this_name->name_space |= NAMESPACE_NFS;
+ goto skip;
+ }
if (stat(this_name->filename, &st) != 0) {
fprintf(stderr,_("Cannot stat %s: %s\n"), this_name->filename,
@@ -388,6 +453,16 @@ int parse_mounts(struct names *this_name
}
}
return 0;
+skip:
+ match_device = -1;
+ for (mountptr = mounts ; mountptr != NULL ; mountptr = mountptr->next) {
+ if (strcmp(mountptr->dir, real) == 0) {
+ /*printf("Debug: adding parse_mounts() adding %s\n",
+ this_name->filename);*/
+ add_device(dev_list, this_name, match_device);
+ }
+ }
+ return 0;
}
#ifdef WITH_IPV6
@@ -652,6 +727,150 @@ void find_net6_sockets(struct inode_list
}
#endif
+/*
+ * Remove struct nfs_points and its sahdows from memory
+ */
+static void clear_shadow(struct shadow_list *restrict shadow)
+{
+ struct shadow_list *s, *n, *l;
+
+ n = shadow;
+ l = (struct shadow_list*)0;
+ for (s = shadow; n; s = n) {
+ l = s->prev;
+ n = s->next;
+ if (s == shadow) {
+ if (n) n->prev = (struct shadow_list*)0;
+ shadow = n;
+ } else if (l) {
+ if (n) n->prev = l;
+ l->next = n;
+ }
+ free(s);
+ }
+}
+
+static void clear_mnt(void)
+{
+ struct nfs_points *p, *n, *l;
+
+ n = mnts;
+ l = (struct nfs_points*)0;
+ for (p = mnts; n; p = n) {
+ l = p->prev;
+ n = p->next;
+ if (p == mnts) {
+ if (n) n->prev = (struct nfs_points*)0;
+ mnts = n;
+ } else if (l) {
+ if (n) n->prev = l;
+ l->next = n;
+ }
+ if (p->shadow)
+ clear_shadow(p->shadow);
+ free(p);
+ }
+}
+
+/*
+ * Check if path is ia shadow off a NFS partition.
+ */
+static int shadow(struct shadow_list *restrict this, const char *restrict name, const size_t nlen)
+{
+ struct shadow_list *s;
+
+ if (!this)
+ goto out;
+ for (s = this; s; s = s->next) {
+ if (nlen < s->nlen)
+ continue;
+ if (name[s->nlen] != '\0' && name[s->nlen] != '/')
+ continue;
+ if (strncmp(name, s->name, s->nlen) == 0)
+ return 1;
+ }
+out:
+ return 0;
+}
+
+/*
+ * Check path is located on a NFS partition.
+ */
+static int check4nfs(const char * path, char * real)
+{
+ char buf[PATH_MAX+1];
+ const char *curr;
+ int deep = MAXSYMLINKS;
+
+ if (!mnts) return 0;
+
+ curr = path;
+ do {
+ const char *prev;
+ int len;
+
+ if ((prev = strdupa(curr)) == NULL)
+ return 0;
+
+ errno = 0;
+ if ((len = readlink(curr, buf, PATH_MAX)) < 0)
+ break;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+
+ if (strncmp(prev, "/proc/", 6) == 0) {
+ curr = &buf[0];
+ break; /* /proc/ provides the real path! */
+ }
+
+ if (len > 10) {
+ char *const ptr = &buf[len - 10];
+ if (strcmp(ptr, " (deleted)") == 0) {
+ *ptr = '\0';
+ curr = &buf[0];
+ break; /* Path is deleted from VFS cache */
+ }
+ }
+
+ 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);
+ struct nfs_points *p;
+ for (p = mnts; p; p = p->next) {
+ if (nlen < p->nlen)
+ continue;
+ if (curr[p->nlen] != '\0' && curr[p->nlen] != '/')
+ continue;
+ if (!strncmp(curr, p->name, p->nlen)) {
+ if (shadow(p->shadow, curr, nlen))
+ continue;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
opt_type opts;
@@ -676,6 +895,7 @@ int main(int argc, char *argv[])
int optc;
char *option;
char *nsptr;
+ size_t len;
#ifdef WITH_IPV6
ipv4_only = ipv6_only = 0;
@@ -692,7 +912,6 @@ int main(int argc, char *argv[])
#endif
netdev = find_net_dev();
- scan_mount_devices(opts, &mount_devices);
fill_unix_cache(&unixsockets);
/* getopt doesnt like things like -SIGBLAH */
@@ -782,6 +1001,10 @@ int main(int argc, char *argv[])
}
continue;
}
+
+ if (!mount_devices)
+ scan_mount_devices(opts, &mount_devices);
+
/* File specifications */
if ( (this_name = malloc(sizeof(struct names))) == NULL)
continue;
@@ -828,10 +1051,24 @@ int main(int argc, char *argv[])
break;
default: /* FILE */
this_name->filename = strdup(argv[optc]);
- parse_file(this_name, &match_inodes);
- parse_unixsockets(this_name, &match_inodes, unixsockets);
- if (opts & OPT_MOUNTPOINT || opts & OPT_MOUNTS)
+ len = strlen(this_name->filename);
+ if (len > 1 && this_name->filename[len-1] == '/')
+ this_name->filename[len-1] = '\0';
+ if (len > 1 && this_name->filename[0] != '/') {
+ char pwd[MAX_PATHNAME];
+ if (getcwd(pwd, MAX_PATHNAME-1)) {
+ char *new, *old = this_name->filename;
+ if (asprintf(&new, "%s/%s", (strlen(pwd) > 1 ? pwd : ""), old) > 0) {
+ this_name->filename = new;
+ free(old);
+ }
+ }
+ }
+ parse_file(this_name, &match_inodes, opts);
+ parse_unixsockets(this_name, &match_inodes, unixsockets, netdev, opts);
+ if (opts & (OPT_MOUNTPOINT | OPT_MOUNTS)) {
parse_mounts(this_name, mount_devices, &match_devices, opts);
+ }
break;
}
@@ -872,10 +1109,11 @@ int main(int argc, char *argv[])
#ifdef DEBUG
debug_match_lists(names_head, match_inodes, match_devices);
#endif
- scan_procs(names_head, match_inodes, match_devices, unixsockets, netdev);
+ scan_procs(opts, names_head, match_inodes, match_devices, unixsockets, netdev);
#ifdef NFS_CHECKS
scan_knfsd(names_head, match_devices);
#endif /* NFS_CHECKS */
+ clear_mnt();
return print_matches(names_head,opts, sig_number);
}
@@ -978,7 +1216,7 @@ static int print_matches(struct names *n
}
-static struct stat *get_pidstat(const pid_t pid, const char *filename)
+static struct stat *get_pidstat(const opt_type opts, const pid_t pid, const char *filename, char *real)
{
char pathname[256];
struct stat *st;
@@ -986,6 +1224,10 @@ static struct stat *get_pidstat(const pi
if ( (st = malloc(sizeof(struct stat))) == NULL)
return NULL;
snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
+ if (check4nfs(pathname, real)) {
+ if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0)
+ return NULL;
+ }
if (stat(pathname, st) != 0)
return NULL;
else
@@ -1030,6 +1272,16 @@ static void check_dir(const pid_t pid, c
}
}
for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
+ if (dev_tmp->name->name_space & NAMESPACE_NFS) {
+ char buf[PATH_MAX+1];
+ ssize_t len;
+ if ((len = readlink(filepath, buf, PATH_MAX)) < 0)
+ continue;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+ if (islocatedon(buf, dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid,uid, access);
+ continue;
+ }
if (st.st_dev == dev_tmp->device) {
if (access == ACCESS_FILE && (lstat(filepath, &lst)==0) && (lst.st_mode & S_IWUSR)) {
add_matched_proc(dev_tmp->name, pid,uid, ACCESS_FILEWR|access);
@@ -1039,6 +1291,16 @@ static void check_dir(const pid_t pid, c
}
}
for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
+ if (ino_tmp->name->name_space & NAMESPACE_NFS) {
+ char buf[PATH_MAX+1];
+ ssize_t len;
+ if ((len = readlink(filepath, buf, PATH_MAX)) < 0)
+ continue;
+ buf[len] = '\0'; /* Don't be fooled by readlink(2) */
+ if (islocatedon(buf, ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid,uid, access);
+ continue;
+ }
if (st.st_dev == ino_tmp->device && st.st_ino == ino_tmp->inode) {
if (access == ACCESS_FILE && (lstat(filepath, &lst)==0) && (lst.st_mode & S_IWUSR)) {
add_matched_proc(ino_tmp->name, pid,uid, ACCESS_FILEWR|access);
@@ -1050,6 +1312,8 @@ static void check_dir(const pid_t pid, c
}
} /* while fd_dent */
closedir(dirp);
+ free(dirpath);
+ free(filepath);
}
static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
@@ -1069,13 +1333,36 @@ static void check_map(const pid_t pid, c
while (fgets(line,BUFSIZ, fp)) {
if (sscanf(line, "%*s %*s %*s %x:%x %lld",
&tmp_maj, &tmp_min, &tmp_inode) == 3) {
+ const char * filepath = strchr(line, '/');
tmp_device = tmp_maj * 256 + tmp_min;
- for(dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next)
+ for(dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
+ if (dev_tmp->name->name_space & NAMESPACE_NFS) {
+ char *nl;
+ if (!filepath)
+ continue;
+ if ((nl = strchr(filepath, '\n')))
+ nl = '\0';
+ if (islocatedon(filepath, dev_tmp->name->filename))
+ add_matched_proc(dev_tmp->name, pid,uid, access);
+ continue;
+ }
if (dev_tmp->device == tmp_device)
add_matched_proc(dev_tmp->name, pid, uid, access);
- for(ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next)
+ }
+ for(ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
+ if (ino_tmp->name->name_space & NAMESPACE_NFS) {
+ char *nl;
+ if (!filepath)
+ continue;
+ if ((nl = strchr(filepath, '\n')))
+ nl = '\0';
+ if (islocatedon(filepath, ino_tmp->name->filename))
+ add_matched_proc(ino_tmp->name, pid,uid, access);
+ continue;
+ }
if (ino_tmp->device == tmp_device && ino_tmp->inode == tmp_inode)
add_matched_proc(ino_tmp->name, pid, uid, access);
+ }
}
}
fclose(fp);
@@ -1146,6 +1433,16 @@ void fill_unix_cache(struct unixsocket_l
}
+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;
+}
+
/*
* scan_mount_devices : Create a list of mount points and devices
* This list is used later for matching purposes
@@ -1155,17 +1452,94 @@ void scan_mount_devices(const opt_type o
FILE *mntfp;
struct mntent *mnt_ptr;
struct stat st;
-
- if ( (mntfp = setmntent("/etc/mtab","r")) == NULL) {
+ const char * mtab;
+
+ if (stat("/proc/version", &st) < 0)
+ mtab = "/etc/mtab";
+ else
+ mtab = "/proc/mounts";
+
+ if ( (mntfp = setmntent(mtab,"r")) == NULL) {
fprintf(stderr, _("Cannot open /etc/mtab: %s\n"),
strerror(errno));
return;
}
while ( (mnt_ptr = getmntent(mntfp)) != NULL) {
+ if (isnetfs(mnt_ptr->mnt_type)) {
+ /*
+ * Remember all NFS typed partitions, required to make check4nfs() work.
+ */
+ size_t nlen = strlen(mnt_ptr->mnt_dir);
+ struct nfs_points *restrict p;
+ if (posix_memalign((void*)&p, sizeof(void*), alignof(struct nfs_points)+(nlen+1)) != 0)
+ goto out;
+ p->name = ((char*)p)+alignof(struct nfs_points);
+ p->nlen = nlen;
+ p->shadow = (struct shadow_list*)0;
+
+ strcpy(p->name, mnt_ptr->mnt_dir);
+ if (mnts)
+ mnts->prev = p;
+ p->next = mnts;
+ p->prev = (struct nfs_points*)0;
+ mnts = p;
+ if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0) {
+ add_mount_device(mount_devices, mnt_ptr->mnt_fsname, mnt_ptr->mnt_dir, (dev_t)-1);
+ continue;
+ }
+ if (nfssafe(stat, mnt_ptr->mnt_dir, &st) == 0) {
+ add_mount_device(mount_devices, mnt_ptr->mnt_fsname, mnt_ptr->mnt_dir, st.st_dev);
+ } else {
+ fprintf(stderr, _("Cannot stat file %s: %s\n"), mnt_ptr->mnt_dir, strerror(errno));
+ }
+ continue;
+ }
+ if ((opts & (OPT_MOUNTPOINT|OPT_MOUNTS)) == 0)
+ continue;
if (stat(mnt_ptr->mnt_dir, &st) == 0) {
add_mount_device(mount_devices, mnt_ptr->mnt_fsname, mnt_ptr->mnt_dir, st.st_dev);
+ } else {
+ fprintf(stderr, _("Cannot stat file %s: %s\n"), mnt_ptr->mnt_dir, strerror(errno));
}
}
+ endmntent(mntfp);
+
+ if (!mnts)
+ return;
+
+ if ((mntfp = setmntent("/proc/mounts", "r")) == NULL) {
+ fprintf(stderr, _("Cannot open /etc/mtab: %s\n"), strerror(errno));
+ return;
+ }
+
+ while ((mnt_ptr = getmntent(mntfp)) != NULL) {
+ struct nfs_points *p;
+
+ for (p = mnts; p; p = p->next) {
+ struct shadow_list *s;
+ size_t nlen;
+
+ if (strcmp(mnt_ptr->mnt_dir, p->name) == 0)
+ continue;
+ if (strncmp(mnt_ptr->mnt_dir, p->name, p->nlen) != 0)
+ continue;
+
+ nlen = strlen(mnt_ptr->mnt_dir);
+ if (posix_memalign((void*)&s, sizeof(void*), alignof(struct shadow_list)+(nlen+1)) != 0)
+ goto out;
+ s->name = ((char*)s)+alignof(struct shadow_list);
+ s->nlen = nlen;
+
+ strcpy(s->name, mnt_ptr->mnt_dir);
+ if (p->shadow)
+ p->shadow->prev = s;
+ s->next = p->shadow;
+ s->prev = (struct shadow_list*)0;
+ p->shadow = s;
+ }
+ }
+out:
+ endmntent(mntfp);
}
#ifdef DEBUG
@@ -1291,3 +1665,56 @@ static void scan_knfsd(struct names *nam
}
}
#endif /* NFSCHECKS */
+
+static sigjmp_buf jenv;
+static int timeout = 5;
+static void sigalarm(int sig)
+{
+ if (sig == SIGALRM)
+ siglongjmp(jenv, 1);
+}
+static int nfssafe(stat_t func, const char *path, struct stat *buf)
+{
+ pid_t pid = 0;
+ int ret = 0, pipes[4];
+
+ 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)
+ write(pipes[1], buf, sizeof(struct stat));
+ 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;
+ timeout = 1;
+ goto err;
+ }
+ (void) signal(SIGALRM, sigalarm);
+ (void) alarm(timeout);
+ if (read(pipes[0], buf, sizeof(struct stat)) == 0) {
+ errno = EFAULT;
+ ret = -1;
+ }
+ (void) alarm(0);
+ (void) signal(SIGALRM, SIG_DFL);
+ close(pipes[0]);
+ break;
+ }
+ return ret;
+err:
+ return -1;
+}
--- src/fuser.h
+++ src/fuser.h 2009-03-27 13:23:36.000000000 +0100
@@ -80,9 +80,33 @@ struct unixsocket_list {
struct unixsocket_list *next;
};
+struct shadow_list
+{
+ struct shadow_list *next;
+ struct shadow_list *prev;
+ size_t nlen;
+ char * name;
+};
+
+struct nfs_points {
+ struct nfs_points *next, *prev;
+ struct shadow_list *shadow;
+ size_t nlen;
+ char * name;
+};
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef restrict
+# define restrict __restrict__
+# endif
+#endif
+#define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+
+
#define NAMESPACE_FILE 0
#define NAMESPACE_TCP 1
#define NAMESPACE_UDP 2
+#define NAMESPACE_NFS 4
#define MAX_PATHNAME 200
#define MAX_CMDNAME 16

View File

@ -1,69 +0,0 @@
--- src/pstree.c
+++ src/pstree.c 2009-05-11 13:32:34.749902293 +0200
@@ -60,6 +60,7 @@ extern const char *__progname;
#define UTF_HD "\342\224\254" /* U+252C, Horizontal and down */
#define VT_BEG "\033(0\017" /* use graphic chars */
+#define VT_LEN 4
#define VT_END "\033(B" /* back to normal char set */
#define VT_V "x" /* see UTF definitions above */
#define VT_VR "t"
@@ -220,6 +221,27 @@ out_string (const char *str)
out_char (*str++);
}
+/*
+ * Only affects vt100 line drawing mode: Do not count the strlen of
+ * VT_BEG to prevent doing end-of-line way too early:
+ */
+static void
+out_sym (const char *str)
+{
+ int seq = 0;
+ if (sym == &sym_vt100 && *str == '\033') {
+ seq = 1;
+ if (cur_x <= output_width || !trunc)
+ cur_x -= VT_LEN;
+ }
+ out_string(str);
+ if (seq) {
+ str = VT_END;
+ while (*str)
+ putchar (*str++);
+ }
+}
+
static int
out_int (int x) /* non-negative integers only */
@@ -431,7 +453,11 @@ dump_tree (PROC * current, int level, in
{
for (i = width[lvl] + 1; i; i--)
out_char (' ');
- out_string (lvl == level - 1 ? last ? sym->last_2 : sym->branch_2 :
+ /*
+ * Replace all three symbol-drawing calls with calls to out_sym()
+ * to handle VT100 line drawing sequences if VT100 mode is active:
+ */
+ out_sym (lvl == level - 1 ? last ? sym->last_2 : sym->branch_2 :
more[lvl + 1] ? sym->vert_2 : sym->empty_2);
}
if (rep < 2)
@@ -543,7 +569,7 @@ dump_tree (PROC * current, int level, in
width[level] = comm_len + cur_x - offset + add;
if (cur_x >= output_width && trunc)
{
- out_string (sym->first_3);
+ out_sym (sym->first_3);
out_string ("+");
out_newline ();
}
@@ -570,7 +596,7 @@ dump_tree (PROC * current, int level, in
}
if (first)
{
- out_string (next ? sym->first_3 : sym->single_3);
+ out_sym (next ? sym->first_3 : sym->single_3);
first = 0;
}
dump_tree (walk->child, level + 1, count + 1,

View File

@ -1,11 +0,0 @@
--- src/pstree.c
+++ src/pstree.c
@@ -70,7 +70,7 @@
typedef struct _proc
{
- char comm[COMM_LEN + 1];
+ char comm[COMM_LEN + 2 + 1]; /* add another 2 for thread brackets */
char **argv; /* only used : argv[0] is 1st arg; undef if argc < 1 */
int argc; /* with -a : number of arguments, -1 if swapped */
pid_t pid;

View File

@ -1,148 +0,0 @@
--- doc/fuser.1
+++ doc/fuser.1 2009-05-11 13:49:21.894401999 +0200
@@ -11,6 +11,7 @@ fuser \- identify processes using files
.IR space\ ]
.RB [ \-k
.RB [ \-i ]
+.RB [ \-w ]
.RB [ \- \fISIGNAL
] ]
.IR name " ..."
@@ -74,6 +75,9 @@ other \fBfuser\fP processes. The effecti
.IP \fB\-i\fP
Ask the user for confirmation before killing a process. This option is
silently ignored if \fB\-k\fP is not present too.
+.IP \fB\-w\fP
+Kill only processes which have write access. This option is
+silently ignored if \fB\-k\fP is not present too.
.IP \fB\-l\fP
List all known signal names.
.IP \fB\-m\fP
--- src/fuser.c
+++ src/fuser.c 2009-05-11 13:50:26.796428307 +0200
@@ -69,7 +69,7 @@ static void check_map(const pid_t pid, c
static struct stat *get_pidstat(const opt_type opts, const pid_t pid, const char *filename, char *real);
static uid_t getpiduid(const pid_t pid);
static int print_matches(struct names *names_head, const opt_type opts, const int sig_number);
-static void kill_matched_proc(struct procs *pptr, const opt_type opts, const int sig_number);
+static int kill_matched_proc(struct procs *pptr, const opt_type opts, const int sig_number);
int parse_mount(struct names *this_name, struct device_list **dev_list);
static void add_device(struct device_list **dev_list, struct names *this_name, dev_t device);
@@ -97,7 +97,7 @@ static void usage (const char *errormsg)
fprintf(stderr, "%s\n", errormsg);
fprintf (stderr, _(
- "Usage: fuser [ -fuv ] [ -a | -s ] [ -4 | -6 ] [ -c | -m | -n SPACE ] [ -k [ -i ] [ -SIGNAL ]] NAME...\n"
+ "Usage: fuser [ -fuv ] [ -a | -s ] [ -4 | -6 ] [ -c | -m | -n SPACE ] [ -k [ -i ] [ -w ] [ -SIGNAL ]] NAME...\n"
" fuser -l\n"
" fuser -V\n"
"Show which processes use the named files, sockets, or filesystems.\n\n"
@@ -113,6 +113,7 @@ static void usage (const char *errormsg)
" -SIGNAL send this signal instead of SIGKILL\n"
" -u display user IDs\n"
" -v verbose output\n"
+ " -w kill only processes with write access\n"
" -V display version information\n"));
#ifdef WITH_IPV6
fprintf (stderr, _(
@@ -982,6 +983,9 @@ int main(int argc, char *argv[])
case 'v':
opts |= OPT_VERBOSE;
break;
+ case 'w':
+ opts |= OPT_WRITE;
+ break;
case 'V':
print_version();
return 0;
@@ -1119,6 +1123,7 @@ static int print_matches(struct names *n
int len = 0;
struct passwd *pwent = NULL;
int have_match = 0;
+ int have_kill = 0;
for (nptr = names_head; nptr != NULL ; nptr = nptr->next) {
if (opts & OPT_SILENT) {
@@ -1189,21 +1194,23 @@ static int print_matches(struct names *n
len = 0;
first = 0;
}
- if (opts & OPT_VERBOSE) {
- /* put a newline if showing all files and no procs*/
- if (nptr->matched_procs == NULL && (opts & OPT_ALLFILES))
- putc('\n', stderr);
- } else {
- if (nptr->matched_procs != NULL || (opts & OPT_ALLFILES))
- putc('\n', stderr);
- }
+ if (opts & OPT_VERBOSE) {
+ /* put a newline if showing all files and no procs*/
+ if (nptr->matched_procs == NULL && (opts & OPT_ALLFILES))
+ putc('\n', stderr);
+ } else {
+ if (nptr->matched_procs != NULL || (opts & OPT_ALLFILES))
+ putc('\n', stderr);
+ }
} /* be silent */
if (opts & OPT_KILL)
- kill_matched_proc(nptr->matched_procs, opts, sig_number);
+ have_kill = kill_matched_proc(nptr->matched_procs, opts, sig_number);
} /* next name */
- return (have_match==1?0:1);
-
+ if (opts & OPT_KILL)
+ return (have_kill==1?0:1);
+ else
+ return (have_match==1?0:1);
}
static struct stat *get_pidstat(const opt_type opts, const pid_t pid, const char *filename, char *real)
@@ -1562,21 +1569,26 @@ static int ask(const pid_t pid)
} /* while */
}
-static void kill_matched_proc(struct procs *proc_head, const opt_type opts, const int sig_number)
+static int kill_matched_proc(struct procs *proc_head, const opt_type opts, const int sig_number)
{
struct procs *pptr;
+ int ret = 0;
for (pptr = proc_head ; pptr != NULL ; pptr = pptr->next ) {
if ( (opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
continue;
+ if ((opts & OPT_WRITE) && ((pptr->access & ACCESS_FILEWR) == 0))
+ continue;
if ( kill (pptr->pid, sig_number) < 0) {
fprintf(stderr, _("Could not kill process %d: %s\n"),
pptr->pid,
strerror(errno)
);
+ continue;
}
-
+ ret = 1;
}
+ return ret;
}
static dev_t find_net_dev(void)
--- src/fuser.h
+++ src/fuser.h 2008-08-07 14:26:48.000000000 +0200
@@ -1,6 +1,6 @@
/* Option Flags */
-typedef unsigned char opt_type;
+typedef unsigned short opt_type;
#define OPT_VERBOSE 1
#define OPT_ALLFILES 2
@@ -10,6 +10,7 @@ typedef unsigned char opt_type;
#define OPT_SILENT 32
#define OPT_USER 64
#define OPT_MOUNTPOINT 128
+#define OPT_WRITE 256
struct procs {

View File

@ -1,56 +0,0 @@
--- configure.ac
+++ configure.ac 2009-05-11 13:59:05.145901759 +0200
@@ -1,10 +1,10 @@
dnl Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.61)
+AC_PREREQ(2.60)
AC_INIT([psmisc],[22.7])
AC_CONFIG_SRCDIR([src/comm.h])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_AUX_DIR([config])
-AM_INIT_AUTOMAKE([1.10])
+AM_INIT_AUTOMAKE([1.9.6])
dnl Checks for programs.
AC_PROG_CXX
@@ -67,7 +67,8 @@ AC_CHECK_MEMBERS([struct user_regs_struc
struct user_regs_struct.rax,
struct user_regs_struct.rdi,
struct user_regs_struct.rsi,
- struct user_regs_struct.rdx], [],[], [#include <sys/user.h>])
+ struct user_regs_struct.rdx], [],[], [#include <sys/types.h>
+ #include <sys/user.h>])
AC_CHECK_MEMBERS([struct pt_regs.orig_gpr3,
struct pt_regs.gpr], [],[], [#include <linux/ptrace.h>])
AM_CONDITIONAL(WANT_PEEKFD_I386,
@@ -88,7 +89,7 @@ AM_CONDITIONAL(WANT_PEEKFD_PPC,
dnl Check for language stuff
AM_GNU_GETTEXT([external])
-AM_GNU_GETTEXT_VERSION([0.16.1])
+AM_GNU_GETTEXT_VERSION([0.15])
dnl Checks for library functions.
AC_FUNC_CLOSEDIR_VOID
--- src/fuser.c
+++ src/fuser.c 2008-10-01 18:02:08.000000000 +0200
@@ -149,7 +149,6 @@ static void scan_procs(const opt_type op
{
DIR *topproc_dir;
struct dirent *topproc_dent;
- char *fd_dirpath, *fd_pathname;
struct inode_list *ino_tmp;
struct device_list *dev_tmp;
pid_t pid, my_pid;
@@ -159,11 +158,6 @@ static void scan_procs(const opt_type op
char cwd_real[PATH_MAX+1];
char exe_real[PATH_MAX+1];
- if ( (fd_dirpath = malloc(MAX_PATHNAME)) == NULL)
- return;
- if ( (fd_pathname = malloc(MAX_PATHNAME)) == NULL)
- return;
-
if ( (topproc_dir = opendir("/proc")) == NULL) {
fprintf(stderr, _("Cannot open /proc directory: %s\n"), strerror(errno));
exit(1);

View File

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2b9581bb21ec92d70653240069d4c1dd088c6a7f381dfc6d6590175d8988e823
size 249141

View File

@ -1,12 +0,0 @@
--- src/pstree.c.orig 2008-12-16 11:13:35.000000000 +0100
+++ src/pstree.c 2009-10-08 19:37:59.000000000 +0200
@@ -749,6 +749,9 @@
exit (1);
}
(void) close (fd);
+ /* If we have read the maximum screen length of args, bring it back by one to stop overflow */
+ if (size >= buffer_size)
+ size--;
if (size)
buffer[size++] = 0;
#ifdef WITH_SELINUX

View File

@ -1,3 +1,39 @@
-------------------------------------------------------------------
Tue Jul 13 18:47:35 CEST 2010 - werner@suse.de
- Update to psmisc-22.12
* In fuser, switched the ipv6 and ipv4 checks around Debian #581604
* peekfd configure patch for x86_64 SF#2986027
* peekfd works with ARM and MIPS thanks to patch by Arnaud Patard
* peekfd off-by-one patch applied SF#1948351
* pstree -a doesn't segfault on grsec kernels Debian #588152
* Another attempted at killall -SIGNAME Debian #573924
* fuser -k -m ... won't kill itself Debian #562767
* fuser -NAME fixed SF #2924691, Debian #563388, Gentoo #297423
* Added locale.h include for killall on non NLS SF #2922163
* Reversed normal file fuser -k check Debian #563387
* short option l returned in fuser Debian #539087
* long options terminated with 0s Debian #551833
* fuser only kills normal processes, patch thanks to Erik Li SF# 2892724
* New fuser -M if you REALLY want mount points, patch thanks to
Jeremie LE HEN SF#2899709
* Fixed killall options for VTALRM and ILL Debian #559011
* pstree -a does not compact threads Debian #525632
* new program prtstat which prints contents of /proc/<pid>/stat
Debian #281706
* killall restricts by date. Thanks to George Danchev Debian #544657
* long options terminated in pstree too to stop segfault
* Re-worked fuser getopt again so -KILL options work Gentoo #297423
* Fix off-by-one overflow in pstree SF# 2832375
* Applied patch from Kari Hautio for lazy umount'ed filesystems SF#2545632
* Applied patch from Anonymous SF submitter to fix killall -l
Fixes SF#2002570
* fuser will print mounts,nfs exports and swaps with -v Debian #356655
and SF#533958
* pstree and fuser have long options Debian #517412
* Fixed pstree -a off-by-one error in buffer, Debian #536243
* Changed configure.ac to not use CXX SF# 2789801
------------------------------------------------------------------- -------------------------------------------------------------------
Tue Jul 6 06:30:24 UTC 2010 - bg@novell.com Tue Jul 6 06:30:24 UTC 2010 - bg@novell.com

View File

@ -1,5 +1,5 @@
# #
# spec file for package psmisc (Version 22.7) # spec file for package psmisc (Version 22.12)
# #
# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. # Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany.
# #
@ -26,23 +26,21 @@ License: GPLv2+
Group: System/Monitoring Group: System/Monitoring
PreReq: %fillup_prereq %insserv_prereq PreReq: %fillup_prereq %insserv_prereq
AutoReqProv: on AutoReqProv: on
Version: 22.7 Version: 22.12
Release: 9 Release: 9
Provides: ps:/usr/bin/killall Provides: ps:/usr/bin/killall
Summary: Utilities for managing processes on your system Summary: Utilities for managing processes on your system
Source: http://switch.dl.sourceforge.net/sourceforge/psmisc/psmisc-%{version}.tar.bz2 Source: http://switch.dl.sourceforge.net/sourceforge/psmisc/psmisc-%{version}.tar.bz2
Patch0: %name-22.7.dif Patch0: %name-22.12.dif
Patch1: %name-22.7-pstree.patch Patch1: %name-22.12-tigetstr.patch
Patch2: %name-22.7-nfs4fuser.patch Patch2: %name-22.12-pstree_overflow.patch
Patch3: %name-22.6-netunix.patch Patch3: %name-22.12-pstree.patch
Patch4: %name-22.7-writeonly.patch Patch4: %name-22.12-leaks.patch
Patch5: %name-22.6-fdleak.patch Patch5: %name-22.12-nfs4fuser.patch
Patch6: %name-22.6-tigetstr.patch Patch6: %name-22.12-writeonly.patch
Patch7: %name-22.7-memleaks.patch
Patch8: %name-22.8-to-22.7-backport.patch
Patch9: psmisc-22.7-pstree_overflow.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRoot: %{_tmppath}/%{name}-%{version}-build
%define nopeek s390 s390x ia64 %arm %sparc hppa %define nopeek s390 s390x ia64 %sparc hppa
%description %description
The psmisc package contains utilities for managing processes on your The psmisc package contains utilities for managing processes on your
@ -60,20 +58,17 @@ Authors:
%prep %prep
%setup -q %setup -q
%patch1 -p0 -b .pstree %patch1 -p0 -b .tigetstr
%patch2 -p0 -b .nfs4fuser %patch2 -p0 -b .pstreeovfl
%patch3 -p0 -b .netunix %patch3 -p0 -b .pstree
%patch4 -p0 -b .wrtonly %patch4 -p0 -b .leaks
%patch5 -p0 -b .fdleak %patch5 -p0 -b .nfs4fuser
%patch6 -p0 -b .tigetstr %patch6 -p0 -b .wrtonly
%patch7 -p0 -b .memleaks
%patch0 -p0 %patch0 -p0
%patch8 -p0
%patch9 -p0
%build %build
autoreconf -fi autoreconf -fi
CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 ${RPM_OPT_FLAGS} -pipe" CFLAGS="-D_GNU_SOURCE ${RPM_OPT_FLAGS} -pipe"
CXXFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS"
CC=gcc CC=gcc
CXX=g++ CXX=g++
@ -100,6 +95,7 @@ rm -rf $RPM_BUILD_ROOT
%ifnarch %nopeek %ifnarch %nopeek
%{_bindir}/peekfd %{_bindir}/peekfd
%endif %endif
%{_bindir}/prtstat
%{_bindir}/pstree %{_bindir}/pstree
%{_bindir}/pstree.x11 %{_bindir}/pstree.x11
%{_mandir}/man1/fuser.1* %{_mandir}/man1/fuser.1*
@ -107,6 +103,7 @@ rm -rf $RPM_BUILD_ROOT
%ifnarch %nopeek %ifnarch %nopeek
%{_mandir}/man1/peekfd.1* %{_mandir}/man1/peekfd.1*
%endif %endif
%{_mandir}/man1/prtstat.1*
%{_mandir}/man1/pstree.1* %{_mandir}/man1/pstree.1*
%changelog %changelog