Hi Denis,

attached is a patch for the fuser applet. Please review and consider usage.

function                                             old     new   delta
scan_proc_net_or_maps                                  -     409    +409
scan_recursive                                         -     399    +399
.rodata                                           148456  148539     +83
search_dev_inode                                      56      53      -3
add_pid                                               51       -     -51
scan_link                                             52       -     -52
scan_dir_links                                       106       -    -106
scan_pid_maps                                        230       -    -230
fuser_main                                           907     365    -542
------------------------------------------------------------------------------
(add/remove: 2/4 grow/shrink: 1/2 up/down: 891/-984)          Total: -93 bytes
   text    data     bss     dec     hex filename
 928597    4122    9568  942287   e60cf busybox_old
 928432    4122    9568  942122   e602a busybox_unstripped


Max
diff --git a/procps/fuser.c b/procps/fuser.c
index 7837ff8..c6529e0 100644
--- a/procps/fuser.c
+++ b/procps/fuser.c
@@ -31,39 +31,42 @@ enum {
 	OPT_IP4    = (1 << 4),
 };
 
+enum {
+	PROC_NET = 0,
+
+	PROC_DIR,
+	PROC_DIR_LINKS,
+	PROC_SUBDIR_LINKS,
+
+	CWD_LINK = 0,
+	EXE_LINK,
+	ROOT_LINK,
+
+	FD_DIR_LINKS,
+	LIB_DIR_LINKS,
+	MMAP_DIR_LINKS,
+
+	MAPS,
+};
+
 typedef struct inode_list {
 	struct inode_list *next;
 	ino_t inode;
 	dev_t dev;
 } inode_list;
 
-typedef struct pid_list {
-	struct pid_list *next;
-	pid_t pid;
-} pid_list;
-
-
 struct globals {
-	pid_list *pid_list_head;
+	int recursion_depth;
+	pid_t mypid;
 	inode_list *inode_list_head;
+	smallint kill_fail;
+	int killsig;
 } FIX_ALIASING;
 #define G (*(struct globals*)&bb_common_bufsiz1)
-#define INIT_G() do { } while (0)
-
-
-static void add_pid(const pid_t pid)
-{
-	pid_list **curr = &G.pid_list_head;
-
-	while (*curr) {
-		if ((*curr)->pid == pid)
-			return;
-		curr = &(*curr)->next;
-	}
-
-	*curr = xzalloc(sizeof(pid_list));
-	(*curr)->pid = pid;
-}
+#define INIT_G() do { \
+	G.mypid = getpid(); \
+	G.killsig = SIGKILL; \
+} while (0)
 
 static void add_inode(const struct stat *st)
 {
@@ -83,48 +86,7 @@ static void add_inode(const struct stat *st)
 	(*curr)->inode = st->st_ino;
 }
 
-static void scan_proc_net(const char *path, unsigned port)
-{
-	char line[MAX_LINE + 1];
-	long long uint64_inode;
-	unsigned tmp_port;
-	FILE *f;
-	struct stat st;
-	int fd;
-
-	/* find socket dev */
-	st.st_dev = 0;
-	fd = socket(AF_INET, SOCK_DGRAM, 0);
-	if (fd >= 0) {
-		fstat(fd, &st);
-		close(fd);
-	}
-
-	f = fopen_for_read(path);
-	if (!f)
-		return;
-
-	while (fgets(line, MAX_LINE, f)) {
-		char addr[68];
-		if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x "
-				"%*x:%*x %*x %*d %*d %llu",
-				addr, &tmp_port, &uint64_inode) == 3
-		) {
-			int len = strlen(addr);
-			if (len == 8 && (option_mask32 & OPT_IP6))
-				continue;
-			if (len > 8 && (option_mask32 & OPT_IP4))
-				continue;
-			if (tmp_port == port) {
-				st.st_ino = uint64_inode;
-				add_inode(&st);
-			}
-		}
-	}
-	fclose(f);
-}
-
-static int search_dev_inode(const struct stat *st)
+static smallint search_dev_inode(const struct stat *st)
 {
 	inode_list *ilist = G.inode_list_head;
 
@@ -140,104 +102,161 @@ static int search_dev_inode(const struct stat *st)
 	return 0;
 }
 
-static void scan_pid_maps(const char *fname, pid_t pid)
+static smallint scan_proc_net_or_maps(const char *path, unsigned port)
 {
-	FILE *file;
-	char line[MAX_LINE + 1];
-	int major, minor;
+	FILE *f;
+	char line[MAX_LINE + 1], addr[68];
+	int major, minor, r;
 	long long uint64_inode;
+	unsigned tmp_port;
+	smallint retval;
 	struct stat st;
+	const char *fmt;
+	void *fag, *sag;
 
-	file = fopen_for_read(fname);
-	if (!file)
-		return;
+	f = fopen_for_read(path);
+	if (!f)
+		return 0;
+
+	if (G.recursion_depth == PROC_NET) {
+		int fd;
+	
+		/* find socket dev */
+		st.st_dev = 0;
+		fd = socket(AF_INET, SOCK_DGRAM, 0);
+		if (fd >= 0) {
+			fstat(fd, &st);
+			close(fd);
+		}
 
-	while (fgets(line, MAX_LINE, file)) {
-		if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3)
-			continue;
-		st.st_ino = uint64_inode;
-		if (major == 0 && minor == 0 && st.st_ino == 0)
-			continue;
-		st.st_dev = makedev(major, minor);
-		if (search_dev_inode(&st))
-			add_pid(pid);
+		fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
+			"%*x:%*x %*x:%*x %*x %*d %*d %llu";
+		fag = addr;
+		sag = &tmp_port;
+	} else {
+		fmt = "%*s %*s %*s %x:%x %llu";
+		fag = &major;
+		sag = &minor;
 	}
-	fclose(file);
-}
 
-static void scan_link(const char *lname, pid_t pid)
-{
-	struct stat st;
+	retval = 0;
+	while (fgets(line, MAX_LINE, f)) {
+		r = sscanf(line, fmt, fag, sag, &uint64_inode);
+		if (r != 3)
+			continue;
 
-	if (stat(lname, &st) >= 0) {
-		if (search_dev_inode(&st))
-			add_pid(pid);
+		st.st_ino = uint64_inode;
+		if (G.recursion_depth == PROC_NET) {
+			r = strlen(addr);
+			if (r == 8 && (option_mask32 & OPT_IP6))
+				continue;
+			if (r > 8 && (option_mask32 & OPT_IP4))
+				continue;
+			if (tmp_port == port)
+				add_inode(&st);
+		} else {
+			if (major != 0 && minor != 0 && st.st_ino != 0) {
+				st.st_dev = makedev(major, minor);
+				if (search_dev_inode(&st)) {
+					retval = 1;
+					break;
+				}
+			}
+		}
 	}
-}
-
-static void scan_dir_links(const char *dname, pid_t pid)
-{
-	DIR *d;
-	struct dirent *de;
-	char *lname;
-
-	d = opendir(dname);
-	if (!d)
-		return;
+	fclose(f);
 
-	while ((de = readdir(d)) != NULL) {
-		lname = concat_subpath_file(dname, de->d_name);
-		if (lname == NULL)
-			continue;
-		scan_link(lname, pid);
-		free(lname);
-	}
-	closedir(d);
+	return retval;
 }
 
-/* NB: does chdir internally */
-static void scan_proc_pids(void)
+static smallint scan_recursive(const char *path)
 {
 	DIR *d;
-	struct dirent *de;
+	struct dirent *d_ent;
+	struct stat st;
+	char *subpath;
 	pid_t pid;
-
-	xchdir("/proc");
-	d = opendir("/proc");
-	if (!d)
-		return;
-
-	while ((de = readdir(d)) != NULL) {
-		pid = (pid_t)bb_strtou(de->d_name, NULL, 10);
-		if (errno)
+	smallint stop_scan;
+	smallint retval;
+
+	d = opendir(path);
+	if (d == NULL)
+		return 0;
+
+	retval = 0;
+	stop_scan = 0;
+	G.recursion_depth++;
+	while(!stop_scan && (d_ent = readdir(d)) != NULL) {
+		subpath = concat_subpath_file(path, d_ent->d_name);
+		if (subpath == NULL)
 			continue;
-		if (chdir(de->d_name) < 0)
-			continue;
-		scan_link("cwd", pid);
-		scan_link("exe", pid);
-		scan_link("root", pid);
-
-		scan_dir_links("fd", pid);
-		scan_dir_links("lib", pid);
-		scan_dir_links("mmap", pid);
-
-		scan_pid_maps("maps", pid);
-		xchdir("/proc");
+		switch(G.recursion_depth) {
+		case PROC_DIR:
+			pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
+			if (errno != 0
+			  || pid == G.mypid
+			  || !scan_recursive(subpath)
+			) {
+				break;
+			}
+			if (option_mask32 & OPT_KILL) {
+				if (kill(pid, G.killsig) != 0) {
+					bb_perror_msg("kill pid %s", d_ent->d_name);
+					G.kill_fail = 1;
+				}
+			}
+			if (!(option_mask32 & OPT_SILENT))
+				printf("%s ", d_ent->d_name);
+			retval = 1;
+			break;
+		case PROC_DIR_LINKS:
+			switch (
+			  index_in_substrings(
+			    "cwd"  "\0" "exe"  "\0"
+			    "root" "\0" "fd"   "\0"
+			    "lib"  "\0" "mmap" "\0"
+			    "maps" "\0", d_ent->d_name
+			  )
+			) {
+			case CWD_LINK:
+			case EXE_LINK:
+			case ROOT_LINK:
+				goto scan_link;
+			case FD_DIR_LINKS:
+			case LIB_DIR_LINKS:
+			case MMAP_DIR_LINKS:
+				if (scan_recursive(subpath)) {
+					stop_scan = 1;
+					retval = 1;
+				}
+				break;
+			case MAPS:
+				if (scan_proc_net_or_maps(subpath, 0)) {
+					stop_scan = 1;
+					retval = 1;
+				}
+			default:
+				break;
+			}
+			break;
+		case PROC_SUBDIR_LINKS:
+  scan_link:
+			if (stat(subpath, &st) < 0)
+				break;
+			if (search_dev_inode(&st)) {
+				stop_scan = 1;
+				retval = 1;
+			}
+		default:
+			break;
+		}
+		free(subpath);
 	}
 	closedir(d);
+	G.recursion_depth--;
+	return retval;
 }
 
-int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int fuser_main(int argc UNUSED_PARAM, char **argv)
-{
-	pid_list *plist;
-	pid_t mypid;
-	char **pp;
-	struct stat st;
-	unsigned port;
-	int opt;
-	int exitcode;
-	int killsig;
 /*
 fuser [OPTIONS] FILE or PORT/PROTO
 Find processes which use FILEs or PORTs
@@ -248,8 +267,17 @@ Find processes which use FILEs or PORTs
         -k      Kill found processes
         -SIGNAL Signal to send (default: KILL)
 */
+int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int fuser_main(int argc UNUSED_PARAM, char **argv)
+{
+	char **pp;
+	struct stat st;
+	unsigned port;
+	int opt;
+
+	INIT_G();
+
 	/* Handle -SIGNAL. Oh my... */
-	killsig = SIGKILL; /* yes, the default is not SIGTERM */
 	pp = argv;
 	while (*++pp) {
 		char *arg = *pp;
@@ -263,7 +291,7 @@ Find processes which use FILEs or PORTs
 		if (opt < 0)
 			continue;
 		/* "-SIGNAL" option found. Remove it and bail out */
-		killsig = opt;
+		G.killsig = opt;
 		do {
 			pp[0] = arg = pp[1];
 			pp++;
@@ -272,7 +300,7 @@ Find processes which use FILEs or PORTs
 	}
 
 	opt_complementary = "-1"; /* at least one param */
-	opt = getopt32(argv, OPTION_STRING);
+	getopt32(argv, OPTION_STRING);
 	argv += optind;
 
 	pp = argv;
@@ -283,7 +311,7 @@ Find processes which use FILEs or PORTs
 			goto file;
 		sprintf(path, "/proc/net/%s", tproto);
 		if (access(path, R_OK) != 0) { /* PORT/PROTO */
-			scan_proc_net(path, port);
+			scan_proc_net_or_maps(path, port);
 		} else { /* FILE */
  file:
 			xstat(*pp, &st);
@@ -292,37 +320,12 @@ Find processes which use FILEs or PORTs
 		pp++;
 	}
 
-	scan_proc_pids(); /* changes dir to "/proc" */
-
-	mypid = getpid();
-	plist = G.pid_list_head;
-	while (1) {
-		if (!plist)
-			return EXIT_FAILURE;
-		if (plist->pid != mypid)
-			break;
-		plist = plist->next;
-	}
-
-	exitcode = EXIT_SUCCESS;
-	do {
-		if (plist->pid != mypid) {
-			if (opt & OPT_KILL) {
-				if (kill(plist->pid, killsig) != 0) {
-					bb_perror_msg("kill pid %u", (unsigned)plist->pid);
-					exitcode = EXIT_FAILURE;
-				}
-			}
-			if (!(opt & OPT_SILENT)) {
-				printf("%u ", (unsigned)plist->pid);
-			}
-		}
-		plist = plist->next;
-	} while (plist);
-
-	if (!(opt & (OPT_SILENT))) {
-		bb_putchar('\n');
+	if (scan_recursive("/proc")) {
+		if (!(option_mask32 & OPT_SILENT))
+			bb_putchar('\n');
+		if (!G.kill_fail)
+			return EXIT_SUCCESS;
 	}
 
-	return exitcode;
+	return EXIT_FAILURE;
 }
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to