fuser: code shrink
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@email.cz> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
e6df7e261e
commit
eeed2306fc
394
procps/fuser.c
394
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);
|
||||
if (G.recursion_depth == PROC_NET) {
|
||||
int fd;
|
||||
|
||||
/* find socket dev */
|
||||
statbuf.st_dev = 0;
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd >= 0) {
|
||||
fstat(fd, &statbuf);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
retval = 0;
|
||||
while (fgets(line, MAX_LINE, f)) {
|
||||
r = sscanf(line, fmt, fag, sag, &uint64_inode);
|
||||
if (r != 3)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void scan_link(const char *lname, pid_t pid)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(lname, &st) >= 0) {
|
||||
if (search_dev_inode(&st))
|
||||
add_pid(pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_dir_links(const char *dname, pid_t pid)
|
||||
static smallint scan_recursive(const char *path)
|
||||
{
|
||||
DIR *d;
|
||||
struct dirent *de;
|
||||
char *lname;
|
||||
struct dirent *d_ent;
|
||||
smallint stop_scan;
|
||||
smallint retval;
|
||||
|
||||
d = opendir(dname);
|
||||
if (!d)
|
||||
return;
|
||||
d = opendir(path);
|
||||
if (d == NULL)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* NB: does chdir internally */
|
||||
static void scan_proc_pids(void)
|
||||
{
|
||||
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);
|
||||
|
||||
scan_pid_maps("maps", pid);
|
||||
xchdir("/proc");
|
||||
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;
|
||||
|
||||
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;
|
||||
if (scan_recursive("/proc")) {
|
||||
if (!(option_mask32 & OPT_SILENT))
|
||||
bb_putchar('\n');
|
||||
return G.kill_failed;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
return exitcode;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user