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;
|
dev_t dev;
|
||||||
} inode_list;
|
} inode_list;
|
||||||
|
|
||||||
typedef struct pid_list {
|
|
||||||
struct pid_list *next;
|
|
||||||
pid_t pid;
|
|
||||||
} pid_list;
|
|
||||||
|
|
||||||
|
|
||||||
struct globals {
|
struct globals {
|
||||||
pid_list *pid_list_head;
|
int recursion_depth;
|
||||||
|
pid_t mypid;
|
||||||
inode_list *inode_list_head;
|
inode_list *inode_list_head;
|
||||||
|
smallint kill_failed;
|
||||||
|
int killsig;
|
||||||
} FIX_ALIASING;
|
} FIX_ALIASING;
|
||||||
#define G (*(struct globals*)&bb_common_bufsiz1)
|
#define G (*(struct globals*)&bb_common_bufsiz1)
|
||||||
#define INIT_G() do { } while (0)
|
#define INIT_G() do { \
|
||||||
|
G.mypid = getpid(); \
|
||||||
|
G.killsig = SIGKILL; \
|
||||||
static void add_pid(const pid_t pid)
|
} while (0)
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_inode(const struct stat *st)
|
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;
|
(*curr)->inode = st->st_ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scan_proc_net(const char *path, unsigned port)
|
static smallint search_dev_inode(const struct stat *st)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
inode_list *ilist = G.inode_list_head;
|
inode_list *ilist = G.inode_list_head;
|
||||||
|
|
||||||
@ -140,130 +84,202 @@ static int search_dev_inode(const struct stat *st)
|
|||||||
return 0;
|
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;
|
FILE *f;
|
||||||
char line[MAX_LINE + 1];
|
char line[MAX_LINE + 1], addr[68];
|
||||||
int major, minor;
|
int major, minor, r;
|
||||||
long long uint64_inode;
|
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);
|
f = fopen_for_read(path);
|
||||||
if (!file)
|
if (!f)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
while (fgets(line, MAX_LINE, file)) {
|
if (G.recursion_depth == PROC_NET) {
|
||||||
if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3)
|
int fd;
|
||||||
continue;
|
|
||||||
st.st_ino = uint64_inode;
|
/* find socket dev */
|
||||||
if (major == 0 && minor == 0 && st.st_ino == 0)
|
statbuf.st_dev = 0;
|
||||||
continue;
|
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
st.st_dev = makedev(major, minor);
|
if (fd >= 0) {
|
||||||
if (search_dev_inode(&st))
|
fstat(fd, &statbuf);
|
||||||
add_pid(pid);
|
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)
|
static smallint scan_recursive(const char *path)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
DIR *d;
|
DIR *d;
|
||||||
struct dirent *de;
|
struct dirent *d_ent;
|
||||||
char *lname;
|
smallint stop_scan;
|
||||||
|
smallint retval;
|
||||||
|
|
||||||
d = opendir(dname);
|
d = opendir(path);
|
||||||
if (!d)
|
if (d == NULL)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
while ((de = readdir(d)) != NULL) {
|
G.recursion_depth++;
|
||||||
lname = concat_subpath_file(dname, de->d_name);
|
retval = 0;
|
||||||
if (lname == NULL)
|
stop_scan = 0;
|
||||||
continue;
|
while (!stop_scan && (d_ent = readdir(d)) != NULL) {
|
||||||
scan_link(lname, pid);
|
struct stat statbuf;
|
||||||
free(lname);
|
pid_t pid;
|
||||||
}
|
char *subpath;
|
||||||
closedir(d);
|
|
||||||
}
|
subpath = concat_subpath_file(path, d_ent->d_name);
|
||||||
|
if (subpath == NULL)
|
||||||
/* NB: does chdir internally */
|
continue; /* . or .. */
|
||||||
static void scan_proc_pids(void)
|
|
||||||
{
|
switch (G.recursion_depth) {
|
||||||
DIR *d;
|
case PROC_DIR:
|
||||||
struct dirent *de;
|
pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
|
||||||
pid_t pid;
|
if (errno != 0
|
||||||
|
|| pid == G.mypid
|
||||||
xchdir("/proc");
|
/* "this PID doesn't use specified FILEs or PORT/PROTO": */
|
||||||
d = opendir("/proc");
|
|| scan_recursive(subpath) == 0
|
||||||
if (!d)
|
) {
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
while ((de = readdir(d)) != NULL) {
|
if (option_mask32 & OPT_KILL) {
|
||||||
pid = (pid_t)bb_strtou(de->d_name, NULL, 10);
|
if (kill(pid, G.killsig) != 0) {
|
||||||
if (errno)
|
bb_perror_msg("kill pid %s", d_ent->d_name);
|
||||||
continue;
|
G.kill_failed = 1;
|
||||||
if (chdir(de->d_name) < 0)
|
}
|
||||||
continue;
|
}
|
||||||
scan_link("cwd", pid);
|
if (!(option_mask32 & OPT_SILENT))
|
||||||
scan_link("exe", pid);
|
printf("%s ", d_ent->d_name);
|
||||||
scan_link("root", pid);
|
retval = 1;
|
||||||
|
break;
|
||||||
scan_dir_links("fd", pid);
|
|
||||||
scan_dir_links("lib", pid);
|
case PROC_DIR_LINKS:
|
||||||
scan_dir_links("mmap", pid);
|
switch (
|
||||||
|
index_in_substrings(
|
||||||
scan_pid_maps("maps", pid);
|
"cwd" "\0" "exe" "\0"
|
||||||
xchdir("/proc");
|
"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);
|
closedir(d);
|
||||||
|
G.recursion_depth--;
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int fuser_main(int argc UNUSED_PARAM, char **argv)
|
int fuser_main(int argc UNUSED_PARAM, char **argv)
|
||||||
{
|
{
|
||||||
pid_list *plist;
|
|
||||||
pid_t mypid;
|
|
||||||
char **pp;
|
char **pp;
|
||||||
struct stat st;
|
|
||||||
unsigned port;
|
INIT_G();
|
||||||
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)
|
|
||||||
*/
|
|
||||||
/* Handle -SIGNAL. Oh my... */
|
/* Handle -SIGNAL. Oh my... */
|
||||||
killsig = SIGKILL; /* yes, the default is not SIGTERM */
|
|
||||||
pp = argv;
|
pp = argv;
|
||||||
while (*++pp) {
|
while (*++pp) {
|
||||||
|
int sig;
|
||||||
char *arg = *pp;
|
char *arg = *pp;
|
||||||
|
|
||||||
if (arg[0] != '-')
|
if (arg[0] != '-')
|
||||||
continue;
|
continue;
|
||||||
if (arg[1] == '-' && arg[2] == '\0') /* "--" */
|
if (arg[1] == '-' && arg[2] == '\0') /* "--" */
|
||||||
break;
|
break;
|
||||||
if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
|
if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
|
||||||
continue; /* it's "-4" or "-6" */
|
continue; /* it's "-4" or "-6" */
|
||||||
opt = get_signum(&arg[1]);
|
sig = get_signum(&arg[1]);
|
||||||
if (opt < 0)
|
if (sig < 0)
|
||||||
continue;
|
continue;
|
||||||
/* "-SIGNAL" option found. Remove it and bail out */
|
/* "-SIGNAL" option found. Remove it and bail out */
|
||||||
killsig = opt;
|
G.killsig = sig;
|
||||||
do {
|
do {
|
||||||
pp[0] = arg = pp[1];
|
pp[0] = arg = pp[1];
|
||||||
pp++;
|
pp++;
|
||||||
@ -272,57 +288,35 @@ Find processes which use FILEs or PORTs
|
|||||||
}
|
}
|
||||||
|
|
||||||
opt_complementary = "-1"; /* at least one param */
|
opt_complementary = "-1"; /* at least one param */
|
||||||
opt = getopt32(argv, OPTION_STRING);
|
getopt32(argv, OPTION_STRING);
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
pp = argv;
|
pp = argv;
|
||||||
while (*pp) {
|
while (*pp) {
|
||||||
/* parse net arg */
|
/* parse net arg */
|
||||||
char path[20], tproto[5];
|
unsigned port;
|
||||||
if (sscanf(*pp, "%u/%4s", &port, tproto) != 2)
|
char path[sizeof("/proc/net/TCP6")];
|
||||||
goto file;
|
|
||||||
sprintf(path, "/proc/net/%s", tproto);
|
strcpy(path, "/proc/net/");
|
||||||
if (access(path, R_OK) != 0) { /* PORT/PROTO */
|
if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
|
||||||
scan_proc_net(path, port);
|
&& access(path, R_OK) != 0
|
||||||
} else { /* FILE */
|
) {
|
||||||
file:
|
/* PORT/PROTO */
|
||||||
xstat(*pp, &st);
|
scan_proc_net_or_maps(path, port);
|
||||||
add_inode(&st);
|
} else {
|
||||||
|
/* FILE */
|
||||||
|
struct stat statbuf;
|
||||||
|
xstat(*pp, &statbuf);
|
||||||
|
add_inode(&statbuf);
|
||||||
}
|
}
|
||||||
pp++;
|
pp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_proc_pids(); /* changes dir to "/proc" */
|
if (scan_recursive("/proc")) {
|
||||||
|
if (!(option_mask32 & OPT_SILENT))
|
||||||
mypid = getpid();
|
bb_putchar('\n');
|
||||||
plist = G.pid_list_head;
|
return G.kill_failed;
|
||||||
while (1) {
|
|
||||||
if (!plist)
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
if (plist->pid != mypid)
|
|
||||||
break;
|
|
||||||
plist = plist->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exitcode = EXIT_SUCCESS;
|
return EXIT_FAILURE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user