File psmisc-22.6-nfs4fuser.patch of Package psmisc

--- 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-03-12 10:21:40.980003767 +0100
@@ -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"
@@ -62,7 +65,7 @@
 static void add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid, const char access);
 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);
 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);
@@ -72,13 +75,18 @@ 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);
+static void scan_procs(const opt_type opts, struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head);
 #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 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)
 {
@@ -127,7 +135,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)
+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)
 {
 	DIR *topproc_dir;
 	struct dirent *topproc_dent;
@@ -137,6 +152,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 +175,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 +187,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 +213,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);
 		check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP);
+#endif
 		check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE);
 		check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
 
@@ -325,10 +362,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 +395,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 +451,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 +725,85 @@ void find_net6_sockets(struct inode_list
 }
 #endif
 
+/*
+ *     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, *n, *l;
+		n = mnts;
+		l = (struct nfs_points*)0;
+		for (p = mnts; 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 main(int argc, char *argv[])
 {
 	opt_type opts; 
@@ -676,6 +828,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 +845,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 +934,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 +984,14 @@ 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';
+				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;
 		}
 
@@ -857,22 +1017,22 @@ int main(int argc, char *argv[])
 	if (!ipv4_only) {
 #endif
 		if (tcp_connection_list != NULL)
-			find_net_sockets(&match_inodes, tcp_connection_list, "tcp",netdev);
+			find_net_sockets(&match_inodes, tcp_connection_list, "tcp", netdev);
 		if (udp_connection_list != NULL)
-			find_net_sockets(&match_inodes, udp_connection_list, "udp",netdev);
+			find_net_sockets(&match_inodes, udp_connection_list, "udp", netdev);
 #ifdef WITH_IPV6
 	}
 	if (!ipv6_only) {
 		if (tcp6_connection_list != NULL)
-			find_net6_sockets(&match_inodes, tcp6_connection_list, "tcp",netdev);
+			find_net6_sockets(&match_inodes, tcp6_connection_list, "tcp", netdev);
 		if (udp6_connection_list != NULL)
-			find_net6_sockets(&match_inodes,  udp6_connection_list, "udp",netdev);
+			find_net6_sockets(&match_inodes,  udp6_connection_list, "udp", netdev);
 	}
 #endif
 #ifdef DEBUG
 	debug_match_lists(names_head, match_inodes, match_devices);
 #endif
-	scan_procs(names_head, match_inodes, match_devices);
+	scan_procs(opts, names_head, match_inodes, match_devices);
 #ifdef NFS_CHECKS
     scan_knfsd(names_head, match_devices);
 #endif /* NFS_CHECKS */
@@ -978,7 +1138,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 +1146,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
@@ -1012,13 +1176,14 @@ static void check_dir(const pid_t pid, c
 	while ( (direntry = readdir(dirp)) != NULL) {
 		if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
 			continue;
-
 		snprintf(filepath, MAX_PATHNAME, "/proc/%d/%s/%s",
 			pid, dirname, direntry->d_name);
 		if (stat(filepath, &st) != 0) {
 			fprintf(stderr, _("Cannot stat file %s: %s\n"),filepath, strerror(errno));
 		} else {
 			for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
+				if (dev_tmp->name->name_space & NAMESPACE_NFS)
+					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);
@@ -1028,6 +1193,8 @@ 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)
+					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);
@@ -1039,6 +1206,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)
@@ -1059,12 +1228,18 @@ static void check_map(const pid_t pid, c
 		if (sscanf(line, "%*s %*s %*s %x:%x %lld", 
 					&tmp_maj, &tmp_min, &tmp_inode) == 3) {
 			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)
+					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)
+					continue;
 				if (ino_tmp->device == tmp_device && ino_tmp->inode == tmp_inode)
 					add_matched_proc(ino_tmp->name, pid, uid, access);
+			}
 		}
 	}
 	fclose(fp);
@@ -1135,6 +1310,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
@@ -1144,17 +1329,53 @@ void scan_mount_devices(const opt_type o
 	FILE *mntfp;
 	struct mntent *mnt_ptr;
 	struct stat st;
-	
-	if ( (mntfp = setmntent("/etc/mtab","r")) == NULL) {
-		fprintf(stderr, _("Cannot open /etc/mtab: %s\n"),
-				strerror(errno));
+
+	if (stat("/proc/version", &st) < 0)
+		mntfp = setmntent("/etc/mtab","r");
+	else
+		mntfp = setmntent("/proc/mounts", "r");
+	if (mntfp == 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.
+			 */
+			struct nfs_points * p = (struct nfs_points*)malloc(sizeof(struct nfs_points));
+			if (!p)
+				goto out;
+			p->name = strdup(mnt_ptr->mnt_dir);
+			if (!p->name)
+				goto out;
+			p->nlen = strlen(p->name);
+			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));
 		}
 	}
+out:
+	endmntent(mntfp);
 }
 
 #ifdef DEBUG
@@ -1280,3 +1501,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	2008-08-07 14:26:48.000000000 +0200
@@ -80,9 +80,16 @@ struct unixsocket_list {
 	struct unixsocket_list *next;
 };
 
+struct nfs_points {
+	struct nfs_points *next, *prev;
+	char * name;
+	size_t nlen;
+};
+
 #define NAMESPACE_FILE 0
 #define NAMESPACE_TCP 1
 #define NAMESPACE_UDP 2
+#define NAMESPACE_NFS 4
 
 #define MAX_PATHNAME 200
 #define MAX_CMDNAME 16
openSUSE Build Service is sponsored by