diff -urN busybox-1.00-pre10.orig/include/applets.h busybox-1.00-pre10/include/applets.h --- busybox-1.00-pre10.orig/include/applets.h 2004-04-06 11:59:43.000000000 -0500 +++ busybox-1.00-pre10/include/applets.h 2004-04-13 12:46:08.000000000 -0500 @@ -223,6 +223,9 @@ #ifdef CONFIG_FTPPUT APPLET(ftpput, ftpgetput_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) #endif +#ifdef CONFIG_FUSER + APPLET(fuser, fuser_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) +#endif #ifdef CONFIG_GETOPT APPLET(getopt, getopt_main, _BB_DIR_BIN, _BB_SUID_NEVER) #endif @@ -355,6 +358,9 @@ #ifdef CONFIG_LS APPLET(ls, ls_main, _BB_DIR_BIN, _BB_SUID_NEVER) #endif +#ifdef CONFIG_FEATURE_FUSER_LSOF + APPLET(lsof, lsof_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) +#endif #ifdef CONFIG_LSMOD APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER) #endif diff -urN busybox-1.00-pre10.orig/include/usage.h busybox-1.00-pre10/include/usage.h --- busybox-1.00-pre10.orig/include/usage.h 2004-04-06 12:52:02.000000000 -0500 +++ busybox-1.00-pre10/include/usage.h 2004-04-13 16:10:45.000000000 -0500 @@ -729,6 +729,17 @@ "\t-p, --password Password to be used\n" \ "\t-P, --port Port number to be used" +#define fuser_trivial_usage \ + "[options] file OR port/proto" +#define fuser_full_usage \ + "Options:\n" \ + "\t-m Show all processes on the same mounted fs\n" \ + "\t-k Kill all processes that match.\n" \ + "\t-s Don't print or kill anything.\n" \ + "\t-4 When using port/proto only search IPv4 space\n" \ + "\t-6 When using port/proto only search IPv6 space\n" \ + "\t-SIGNAL When used with -k, this signal will be used to kill\n" + #define getopt_trivial_usage \ "[OPTIONS]..." #define getopt_full_usage \ @@ -1536,6 +1547,13 @@ USAGE_SELINUX("\t-k\tprint security context\n") \ USAGE_SELINUX("\t-K\tprint security context in long format\n") +#define lsof_trivial_usage \ + "[filelist]" +#define lsof_full_usage \ + "List open files with associated process information.\n" \ + "Specify a filename or list of filenames to only see information\n " \ + "about those files." + #define lsmod_trivial_usage \ "" #define lsmod_full_usage \ diff -urN busybox-1.00-pre10.orig/procps/Config.in busybox-1.00-pre10/procps/Config.in --- busybox-1.00-pre10.orig/procps/Config.in 2003-12-24 00:02:11.000000000 -0600 +++ busybox-1.00-pre10/procps/Config.in 2004-04-13 16:13:25.000000000 -0500 @@ -13,6 +13,24 @@ memory in the system, as well as the buffers used by the kernel. The shared memory column should be ignored; it is obsolete. +config CONFIG_FUSER + bool "fuser" + default n + help + fuser lists all PIDs (Process IDs) that currently have a given + file open. fuser can also list all PIDs that have a given network + (TCP or UDP) port open. + +config CONFIG_FEATURE_FUSER_LSOF + bool " lsof" + default n + depends on CONFIG_FUSER + help + lsof shows open files with associated process information. If + invoked without any parameters it lists ALL open file handles + on the system. It also accepts a filename or list of filenames as + input to narrow the output to only those files. + config CONFIG_KILL bool "kill" default n @@ -78,5 +96,6 @@ help sysctl - configure kernel parameters at runtime + endmenu diff -urN busybox-1.00-pre10.orig/procps/Makefile.in busybox-1.00-pre10/procps/Makefile.in --- busybox-1.00-pre10.orig/procps/Makefile.in 2004-03-15 02:29:03.000000000 -0600 +++ busybox-1.00-pre10/procps/Makefile.in 2004-04-13 11:36:54.000000000 -0500 @@ -31,6 +31,7 @@ PROCPS-$(CONFIG_SYSCTL) += sysctl.o PROCPS-$(CONFIG_TOP) += top.o PROCPS-$(CONFIG_UPTIME) += uptime.o +PROCPS-$(CONFIG_FUSER) += fuser.o libraries-y+=$(PROCPS_DIR)$(PROCPS_AR) diff -urN busybox-1.00-pre10.orig/procps/fuser.c busybox-1.00-pre10/procps/fuser.c --- busybox-1.00-pre10.orig/procps/fuser.c 1969-12-31 18:00:00.000000000 -0600 +++ busybox-1.00-pre10/procps/fuser.c 2004-04-13 16:03:56.000000000 -0500 @@ -0,0 +1,541 @@ +/* + * tiny fuser implementation + * + * Copyright 2004 Tony J. White + * + * May be distributed under the conditions of the + * GNU Library General Public License + */ + +/* this define is needed for asprintf() */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define FUSER_PROC_DIR "/proc" +#define FUSER_MAX_LINE 255 + +#define FUSER_OPT_MOUNT 1 +#define FUSER_OPT_KILL 2 +#define FUSER_OPT_SILENT 4 +#define FUSER_OPT_IP6 8 +#define FUSER_OPT_IP4 16 +#define FUSER_OPT_SHOWALL 32 + +typedef struct inode_list { + ino_t inode; + dev_t dev; + struct inode_list *next; +} inode_list; + +typedef struct pid_list { + pid_t pid; + ino_t inode; + dev_t dev; + char *filename; + struct pid_list *next; +} pid_list; + +static int fuser_option(char *option) +{ + int opt = 0; + + if(!(strlen(option))) return 0; + if(option[0] != '-') return 0; + *++option; + while(*option != '\0') { + if(*option == 'm') opt |= FUSER_OPT_MOUNT; + else if(*option == 'k') opt |= FUSER_OPT_KILL; + else if(*option == 's') opt |= FUSER_OPT_SILENT; + else if(*option == '6') opt |= FUSER_OPT_IP6; + else if(*option == '4') opt |= FUSER_OPT_IP4; + else { + bb_error_msg_and_die( + "Unsupported option '%c'", *option); + } + *++option; + } + return opt; +} + +static int fuser_file_to_dev_inode(const char *filename, + dev_t *dev, ino_t *inode) +{ + struct stat f_stat; + if((stat(filename, &f_stat)) < 0) return 0; + memcpy(inode, &f_stat.st_ino, sizeof(ino_t)); + memcpy(dev, &f_stat.st_dev, sizeof(dev_t)); + return 1; +} + +static int fuser_find_socket_dev(dev_t *dev) { + int fd = socket(PF_INET, SOCK_DGRAM,0); + struct stat buf; + + if (fd >= 0 && (fstat(fd, &buf)) == 0) { + memcpy(dev, &buf.st_dev, sizeof(dev_t)); + close(fd); + return 1; + } + return 0; +} + +static int fuser_parse_net_arg(const char *filename, + const char **proto, int *port) +{ + int tport; + char path[PATH_MAX+1], tproto[5]; + + if((sscanf(filename, "%d/%4s", &tport, &tproto[0])) != 2) return 0; + strncpy(path, FUSER_PROC_DIR, sizeof(FUSER_PROC_DIR)); + strncat(path, "/net/", 5); + strncat(path, tproto, strlen(tproto)); + if((access(path, R_OK)) != 0) return 0; + *proto = bb_xstrndup(tproto, strlen(tproto)); + memcpy(port, &tport, sizeof(int)); + return 1; +} + +static int fuser_add_pid(pid_list *plist, pid_t pid, + dev_t dev, ino_t inode, const char *filename) +{ + pid_list *curr = NULL, *last = NULL; + + if(plist->pid == 0) { + plist->pid = pid; + plist->dev = dev; + plist->inode = inode; + plist->filename = bb_xstrndup(filename, strlen(filename)); + return 1; + } + curr = plist; + while(curr != NULL) { + if(curr->pid == pid && curr->dev == dev && curr->inode == inode) + return 1; + last = curr; + curr = curr->next; + } + curr = xmalloc(sizeof(pid_list)); + last->next = curr; + curr->pid = pid; + curr->dev = dev; + curr->inode = inode; + curr->filename = bb_xstrndup(filename, strlen(filename)); + curr->next = NULL; + return 1; +} + +static int fuser_add_inode(inode_list *ilist, dev_t dev, ino_t inode) +{ + inode_list *curr = NULL, *last = NULL; + + if(!ilist->inode && !ilist->dev) { + ilist->dev = dev; + ilist->inode = inode; + } + curr = ilist; + while(curr != NULL) { + if(curr->inode == inode && curr->dev == dev) return 1; + last = curr; + curr = curr->next; + } + curr = xmalloc(sizeof(inode_list)); + last->next = curr; + curr->dev = dev; + curr->inode = inode; + curr->next = NULL; + return 1; +} + +static int fuser_clear_pid_list(pid_list *plist) +{ + pid_list *curr, *next; + curr = next = plist->next; + while(curr != NULL) { + next = curr->next; + free(curr); + curr = next; + } + plist->pid = 0; + plist->next = NULL; + return 1; +} + +static int fuser_clear_inode_list(inode_list *ilist) +{ + inode_list *curr, *next; + curr = next = ilist->next; + while(curr != NULL) { + next = curr->next; + free(curr); + curr = next; + } + ilist->dev = 0; + ilist->inode = 0; + ilist->next = NULL; + return 1; +} + + +static int fuser_scan_proc_net(int opts, const char *proto, + int port, inode_list *ilist) +{ + char path[PATH_MAX+1], line[FUSER_MAX_LINE+1]; + char addr[128]; + ino_t tmp_inode; + dev_t tmp_dev; + int tmp_port; + FILE *f; + + if(!fuser_find_socket_dev(&tmp_dev)) tmp_dev = 0; + + strncpy(path, FUSER_PROC_DIR, sizeof(FUSER_PROC_DIR)); + strncat(path, "/net/", 5); + strncat(path, proto, strlen(proto)); + + if (!(f = fopen(path, "r"))) return 0; + while(fgets(line, FUSER_MAX_LINE, f)) { + if(sscanf(line, + "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " + "%*x:%*x %*x %*d %*d %lu", + &addr[0], &tmp_port, &tmp_inode) == 3) { + if((strlen(addr) == 8) && + (opts & FUSER_OPT_IP6)) continue; + else if((strlen(addr) > 8) && + (opts & FUSER_OPT_IP4)) continue; + if(tmp_port == port) { + fuser_add_inode(ilist, tmp_dev, tmp_inode); + } + } + + } + fclose(f); + return 1; +} + +static int fuser_search_dev_inode(int opts, inode_list *ilist, + dev_t dev, ino_t inode) +{ + inode_list *curr; + curr = ilist; + + while(curr) { + if((opts & FUSER_OPT_MOUNT) && curr->dev == dev) + return 1; + if(curr->inode == inode && curr->dev == dev) + return 1; + curr = curr->next; + } + return 0; +} + +static int fuser_scan_pid_maps(int opts, const char *fname, pid_t pid, + inode_list *ilist, pid_list *plist) +{ + FILE *file; + char line[FUSER_MAX_LINE + 1]; + int major, minor; + ino_t inode; + dev_t dev; + char filename[FUSER_MAX_LINE]; + + if (!(file = fopen(fname, "r"))) return 0; + while (fgets(line, FUSER_MAX_LINE, file)) { + if(sscanf(line, "%*s %*s %*s %x:%x %ld%*[ \t]%s", + &major, &minor, &inode, &filename[0]) < 3) continue; + if(major == 0 && minor == 0 && inode == 0) continue; + dev = makedev(major, minor); + if((opts & FUSER_OPT_SHOWALL) + || fuser_search_dev_inode(opts, ilist, dev, inode)) { + fuser_add_pid(plist, pid, dev, inode, filename); + } + } + fclose(file); + return 1; +} + +static int fuser_scan_link(int opts, const char *lname, pid_t pid, + inode_list *ilist, pid_list *plist) +{ + ino_t inode; + dev_t dev; + + if(!fuser_file_to_dev_inode(lname, &dev, &inode)) return 0; + + if((opts & FUSER_OPT_SHOWALL) + || fuser_search_dev_inode(opts, ilist, dev, inode)) + fuser_add_pid(plist, pid, dev, inode, xreadlink(lname)); + return 1; +} + +static int fuser_scan_dir_links(int opts, const char *dname, pid_t pid, + inode_list *ilist, pid_list *plist) +{ + DIR *d; + struct dirent *de; + char *lname; + + if((d = opendir(dname))) { + while((de = readdir(d)) != NULL) { + if(!(strcmp(de->d_name, "."))) continue; + if(!(strcmp(de->d_name, ".."))) continue; + if(asprintf(&lname, "%s/%s", dname, de->d_name) < 0) { + free(lname); + continue; + } + fuser_scan_link(opts, lname, pid, ilist, plist); + free(lname); + } + closedir(d); + } + else return 0; + return 1; + +} + +static int fuser_scan_proc_pids(int opts, inode_list *ilist, pid_list *plist) +{ + struct dirent **de; + pid_t pid; + char *dname; + int n = 0, i = 0; + + n = scandir(FUSER_PROC_DIR, &de, 0, versionsort); + if(n < 0) + bb_perror_msg_and_die("could not open procfs dir %s", + FUSER_PROC_DIR); + for(i=0; id_name); + if(!pid) continue; + if(asprintf(&dname, "%s/%d/", FUSER_PROC_DIR, pid) < 0) { + free(dname); + continue; + } + if(chdir(dname) < 0) { + free(dname); + continue; + } + free(dname); + fuser_scan_link(opts, "cwd", pid, ilist, plist); + fuser_scan_link(opts, "exe", pid, ilist, plist); + fuser_scan_link(opts, "root", pid, ilist, plist); + fuser_scan_dir_links(opts, "fd", pid, ilist, plist); + fuser_scan_dir_links(opts, "lib", pid, ilist, plist); + fuser_scan_dir_links(opts, "mmap", pid, ilist, plist); + fuser_scan_pid_maps(opts, "maps", pid, ilist, plist); + } + return 1; +} + +static int fuser_print_pid_list(pid_list *plist) { + pid_list *curr; + curr = plist; + + if(plist == NULL) return 0; + while(curr != NULL) { + if(curr->pid > 0) printf("%d ", curr->pid); + curr = curr->next; + } + printf("\n"); + return 1; +} + +static int fuser_kill_pid_list(pid_list *plist, int sig) { + pid_list *curr; + curr = plist; + pid_t mypid = getpid(); + int success = 1; + + if(plist == NULL) return 0; + while(curr != NULL) { + if(curr->pid > 0 && curr->pid != mypid) { + if (kill(curr->pid, sig) != 0) { + bb_perror_msg( + "Could not kill pid '%d'", curr->pid); + success = 0; + } + } + curr = curr->next; + } + return success; +} + +extern int fuser_main(int argc, char **argv) { + int port, i, optn; + int* fni; /* file name indexes of argv */ + int fnic = 0; /* file name index count */ + const char *proto; + static int opt = 0; /* FUSER_OPT_ */ + dev_t dev; + ino_t inode; + pid_list *pids; + inode_list *inodes; + int killsig = SIGTERM; + int success = 1; + + fni = xmalloc(sizeof(int)); + for(i=1;ipid == 0) success = 0; + if(!success) break; + if(opt & FUSER_OPT_KILL) { + success = fuser_kill_pid_list(pids, killsig); + } + else if(!(opt & FUSER_OPT_SILENT)) { + printf("%s: ", argv[fni[i]]); + success = fuser_print_pid_list(pids); + } + fuser_clear_pid_list(pids); + fuser_clear_inode_list(inodes); + } + /* return 0 on (success == 1) 1 otherwise */ + return (success != 1); +} + +#ifdef CONFIG_FEATURE_FUSER_LSOF + +static int lsof_option(char *option) +{ + if(!(strlen(option))) return 0; + if(option[0] != '-') return 0; + /* see fuser_option() for an example on how to add options + currently none are supported */ + bb_error_msg_and_die("Unsupported option '%c'", *option); + return 0; +} + +static int lsof_print_pid_list(pid_list *plist) { + pid_list *curr; + procps_status_t *ps, *ps_tmp; + int nps = 0, n = 0; + char *devstr; + + curr = plist; + if(plist == NULL) return 0; + ps = xmalloc(sizeof(procps_status_t)); +#ifdef CONFIG_SELINUX + while ((ps_tmp = procps_scan(0, 0, NULL) ) != 0) { +#else + while ((ps_tmp = procps_scan(0)) != 0) { +#endif + n = nps; + ps = xrealloc(ps, (++nps)*sizeof(procps_status_t)); + memcpy(ps + n, ps_tmp, sizeof(procps_status_t)); + } + + if(curr != NULL) { + printf("COMMAND PID USER DEVICE NODE NAME\n"); + } + while(curr != NULL) { + if(curr->pid > 0) { + for(n = 0; n < nps; n++) { + ps_tmp = ps + n; + if(ps_tmp->pid == curr->pid) { + printf("%-9.9s ", ps_tmp->short_cmd); + printf("%6d ", curr->pid); + printf("%7.7s ", ps_tmp->user); + } + } + asprintf(&devstr, "%d,%d", + major(curr->dev), minor(curr->dev)); + printf("%6.6s", devstr); + free(devstr); + printf("%10ld ", curr->inode); + printf("%s\n", curr->filename); + } + curr = curr->next; + } + printf("\n"); + return 1; +} + +extern int lsof_main(int argc, char **argv) { + int i, optn; + int* fni; /* file name indexes of argv */ + int fnic = 0; /* file name index count */ + static int opt = 0; /* FUSER_OPT_ */ + dev_t dev; + ino_t inode; + pid_list *pids; + inode_list *inodes; + int success = 1; + + fni = xmalloc(sizeof(int)); + for(i=1;ipid == 0) success = 0; + if(!success) break; + success = lsof_print_pid_list(pids); + fuser_clear_pid_list(pids); + fuser_clear_inode_list(inodes); + } + } + /* return 0 on (success == 1) 1 otherwise */ + return (success != 1); +} +#endif /* CONFIG_FEATURE_FUSER_LSOF */