[git commit] fuser: code shrink

Denys Vlasenko vda.linux at googlemail.com
Mon May 23 01:39:48 UTC 2011


commit: http://git.busybox.net/busybox/commit/?id=eeed2306fceacf2baea77712b309b4fa40e671b6
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
scan_proc_net_or_maps                                  -     427    +427
scan_recursive                                         -     380    +380
search_dev_inode                                      74      71      -3
add_pid                                               39       -     -39
scan_link                                             46       -     -46
scan_dir_links                                        76       -     -76
scan_pid_maps                                        222       -    -222
fuser_main                                           871     297    -574
------------------------------------------------------------------------------
(add/remove: 2/4 grow/shrink: 0/2 up/down: 807/-960)         Total: -153 bytes

Signed-off-by: Maksym Kryzhanovskyy <xmaks at email.cz>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 procps/fuser.c |  386 ++++++++++++++++++++++++++++----------------------------
 1 files changed, 190 insertions(+), 196 deletions(-)

diff --git a/procps/fuser.c b/procps/fuser.c
index 7837ff8..2a7c310 100644
--- a/procps/fuser.c
+++ b/procps/fuser.c
@@ -37,33 +37,18 @@ typedef struct inode_list {
 	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_failed;
+	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 +68,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,130 +84,202 @@ static int search_dev_inode(const struct stat *st)
 	return 0;
 }
 
-static void scan_pid_maps(const char *fname, pid_t pid)
+enum {
+	PROC_NET = 0,
+	PROC_DIR,
+	PROC_DIR_LINKS,
+	PROC_SUBDIR_LINKS,
+};
+
+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;
-	struct stat st;
+	unsigned tmp_port;
+	smallint retval;
+	struct stat statbuf;
+	const char *fmt;
+	void *fag, *sag;
 
-	file = fopen_for_read(fname);
-	if (!file)
-		return;
+	f = fopen_for_read(path);
+	if (!f)
+		return 0;
 
-	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);
-	}
-	fclose(file);
-}
+	if (G.recursion_depth == PROC_NET) {
+		int fd;
 
-static void scan_link(const char *lname, pid_t pid)
-{
-	struct stat st;
+		/* find socket dev */
+		statbuf.st_dev = 0;
+		fd = socket(AF_INET, SOCK_DGRAM, 0);
+		if (fd >= 0) {
+			fstat(fd, &statbuf);
+			close(fd);
+		}
 
-	if (stat(lname, &st) >= 0) {
-		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;
 	}
-}
-
-static void scan_dir_links(const char *dname, pid_t pid)
-{
-	DIR *d;
-	struct dirent *de;
-	char *lname;
-
-	d = opendir(dname);
-	if (!d)
-		return;
 
-	while ((de = readdir(d)) != NULL) {
-		lname = concat_subpath_file(dname, de->d_name);
-		if (lname == NULL)
+	retval = 0;
+	while (fgets(line, MAX_LINE, f)) {
+		r = sscanf(line, fmt, fag, sag, &uint64_inode);
+		if (r != 3)
 			continue;
-		scan_link(lname, pid);
-		free(lname);
+
+		statbuf.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(&statbuf);
+		} else {
+			if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
+				statbuf.st_dev = makedev(major, minor);
+				retval = search_dev_inode(&statbuf);
+				if (retval)
+					break;
+			}
+		}
 	}
-	closedir(d);
+	fclose(f);
+
+	return retval;
 }
 
-/* NB: does chdir internally */
-static void scan_proc_pids(void)
+static smallint scan_recursive(const char *path)
 {
 	DIR *d;
-	struct dirent *de;
-	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)
-			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);
+	struct dirent *d_ent;
+	smallint stop_scan;
+	smallint retval;
+
+	d = opendir(path);
+	if (d == NULL)
+		return 0;
+
+	G.recursion_depth++;
+	retval = 0;
+	stop_scan = 0;
+	while (!stop_scan && (d_ent = readdir(d)) != NULL) {
+		struct stat statbuf;
+		pid_t pid;
+		char *subpath;
+
+		subpath = concat_subpath_file(path, d_ent->d_name);
+		if (subpath == NULL)
+			continue; /* . or .. */
+
+		switch (G.recursion_depth) {
+		case PROC_DIR:
+			pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
+			if (errno != 0
+			 || pid == G.mypid
+			/* "this PID doesn't use specified FILEs or PORT/PROTO": */
+			 || scan_recursive(subpath) == 0
+			) {
+				break;
+			}
+			if (option_mask32 & OPT_KILL) {
+				if (kill(pid, G.killsig) != 0) {
+					bb_perror_msg("kill pid %s", d_ent->d_name);
+					G.kill_failed = 1;
+				}
+			}
+			if (!(option_mask32 & OPT_SILENT))
+				printf("%s ", d_ent->d_name);
+			retval = 1;
+			break;
 
-		scan_pid_maps("maps", pid);
-		xchdir("/proc");
+		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
+				)
+			) {
+			enum {
+				CWD_LINK,
+				EXE_LINK,
+				ROOT_LINK,
+				FD_DIR_LINKS,
+				LIB_DIR_LINKS,
+				MMAP_DIR_LINKS,
+				MAPS,
+			};
+			case CWD_LINK:
+			case EXE_LINK:
+			case ROOT_LINK:
+				goto scan_link;
+			case FD_DIR_LINKS:
+			case LIB_DIR_LINKS:
+			case MMAP_DIR_LINKS:
+				stop_scan = scan_recursive(subpath);
+				if (stop_scan)
+					retval = stop_scan;
+				break;
+			case MAPS:
+				stop_scan = scan_proc_net_or_maps(subpath, 0);
+				if (stop_scan)
+					retval = stop_scan;
+			default:
+				break;
+			}
+			break;
+		case PROC_SUBDIR_LINKS:
+  scan_link:
+			if (stat(subpath, &statbuf) < 0)
+				break;
+			stop_scan = search_dev_inode(&statbuf);
+			if (stop_scan)
+				retval = stop_scan;
+		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
-        -m      Find processes which use same fs as FILEs
-        -4      Search only IPv4 space
-        -6      Search only IPv6 space
-        -s      Don't display PIDs
-        -k      Kill found processes
-        -SIGNAL Signal to send (default: KILL)
-*/
+
+	INIT_G();
+
 	/* Handle -SIGNAL. Oh my... */
-	killsig = SIGKILL; /* yes, the default is not SIGTERM */
 	pp = argv;
 	while (*++pp) {
+		int sig;
 		char *arg = *pp;
+
 		if (arg[0] != '-')
 			continue;
 		if (arg[1] == '-' && arg[2] == '\0') /* "--" */
 			break;
 		if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
 			continue; /* it's "-4" or "-6" */
-		opt = get_signum(&arg[1]);
-		if (opt < 0)
+		sig = get_signum(&arg[1]);
+		if (sig < 0)
 			continue;
 		/* "-SIGNAL" option found. Remove it and bail out */
-		killsig = opt;
+		G.killsig = sig;
 		do {
 			pp[0] = arg = pp[1];
 			pp++;
@@ -272,57 +288,35 @@ 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;
 	while (*pp) {
 		/* parse net arg */
-		char path[20], tproto[5];
-		if (sscanf(*pp, "%u/%4s", &port, tproto) != 2)
-			goto file;
-		sprintf(path, "/proc/net/%s", tproto);
-		if (access(path, R_OK) != 0) { /* PORT/PROTO */
-			scan_proc_net(path, port);
-		} else { /* FILE */
- file:
-			xstat(*pp, &st);
-			add_inode(&st);
+		unsigned port;
+		char path[sizeof("/proc/net/TCP6")];
+
+		strcpy(path, "/proc/net/");
+		if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
+		 && access(path, R_OK) != 0
+		) {
+			/* PORT/PROTO */
+			scan_proc_net_or_maps(path, port);
+		} else {
+			/* FILE */
+			struct stat statbuf;
+			xstat(*pp, &statbuf);
+			add_inode(&statbuf);
 		}
 		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');
+		return G.kill_failed;
 	}
 
-	return exitcode;
+	return EXIT_FAILURE;
 }
-- 
1.7.3.4



More information about the busybox-cvs mailing list