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