fuser: code shrink
No binary (build failed)
—
(log yok)
| @@ -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; |
| } | |