1
/* vi: set sw=4 ts=4: */
3
* tiny fuser implementation
5
* Copyright 2004 Tony J. White
7
* Licensed under GPLv2, see file LICENSE in this source tree.
10
//config: bool "fuser (7.3 kb)"
13
//config: fuser lists all PIDs (Process IDs) that currently have a given
14
//config: file open. fuser can also list all PIDs that have a given network
15
//config: (TCP or UDP) port open.
17
//applet:IF_FUSER(APPLET(fuser, BB_DIR_USR_BIN, BB_SUID_DROP))
19
//kbuild:lib-$(CONFIG_FUSER) += fuser.o
21
//usage:#define fuser_trivial_usage
22
//usage: "[-msk46] [-SIGNAL] FILE or PORT/PROTO"
23
//usage:#define fuser_full_usage "\n\n"
24
//usage: "Find processes which use FILEs or PORTs\n"
25
//usage: "\n -m Find processes which use same fs as FILEs"
26
//usage: "\n -4,-6 Search only IPv4/IPv6 space"
27
//usage: "\n -s Don't display PIDs"
28
//usage: "\n -k Kill found processes"
29
//usage: "\n -SIGNAL Signal to send (default: KILL)"
32
#include "common_bufsiz.h"
36
#define OPTION_STRING "mks64"
40
OPT_SILENT = (1 << 2),
45
typedef struct inode_list {
46
struct inode_list *next;
54
inode_list *inode_list_head;
58
#define G (*(struct globals*)bb_common_bufsiz1)
59
#define INIT_G() do { \
60
setup_common_bufsiz(); \
62
G.killsig = SIGKILL; \
65
static void add_inode(const struct stat *st)
67
inode_list **curr = &G.inode_list_head;
70
if ((*curr)->dev == st->st_dev
71
&& (*curr)->inode == st->st_ino
75
curr = &(*curr)->next;
78
*curr = xzalloc(sizeof(inode_list));
79
(*curr)->dev = st->st_dev;
80
(*curr)->inode = st->st_ino;
83
static smallint search_dev_inode(const struct stat *st)
85
inode_list *ilist = G.inode_list_head;
88
if (ilist->dev == st->st_dev) {
89
if (option_mask32 & OPT_MOUNT)
91
if (ilist->inode == st->st_ino)
106
static smallint scan_proc_net_or_maps(const char *path, unsigned port)
109
char line[MAX_LINE + 1], addr[68];
111
long long uint64_inode;
118
f = fopen_for_read(path);
122
if (G.recursion_depth == PROC_NET) {
125
/* find socket dev */
127
fd = socket(AF_INET, SOCK_DGRAM, 0);
133
fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
134
"%*x:%*x %*x:%*x %*x %*d %*d %llu";
138
fmt = "%*s %*s %*s %x:%x %llu";
144
while (fgets(line, MAX_LINE, f)) {
145
r = sscanf(line, fmt, fag, sag, &uint64_inode);
149
statbuf.st_ino = uint64_inode;
150
if (G.recursion_depth == PROC_NET) {
152
if (r == 8 && (option_mask32 & OPT_IP6))
154
if (r > 8 && (option_mask32 & OPT_IP4))
156
if (tmp_port == port)
159
if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
160
statbuf.st_dev = makedev(major, minor);
161
retval = search_dev_inode(&statbuf);
172
static smallint scan_recursive(const char *path)
175
struct dirent *d_ent;
186
while (!stop_scan && (d_ent = readdir(d)) != NULL) {
191
subpath = concat_subpath_file(path, d_ent->d_name);
193
continue; /* . or .. */
195
switch (G.recursion_depth) {
197
pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
200
/* "this PID doesn't use specified FILEs or PORT/PROTO": */
201
|| scan_recursive(subpath) == 0
205
if (option_mask32 & OPT_KILL) {
206
if (kill(pid, G.killsig) != 0) {
207
bb_perror_msg("kill pid %s", d_ent->d_name);
211
if (!(option_mask32 & OPT_SILENT))
212
printf("%s ", d_ent->d_name);
219
"cwd" "\0" "exe" "\0"
220
"root" "\0" "fd" "\0"
221
"lib" "\0" "mmap" "\0"
242
stop_scan = scan_recursive(subpath);
247
stop_scan = scan_proc_net_or_maps(subpath, 0);
254
case PROC_SUBDIR_LINKS:
256
if (stat(subpath, &statbuf) < 0)
258
stop_scan = search_dev_inode(&statbuf);
271
int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
272
int fuser_main(int argc UNUSED_PARAM, char **argv)
278
/* Handle -SIGNAL. Oh my... */
286
if (arg[1] == '-' && arg[2] == '\0') /* "--" */
288
if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
289
continue; /* it's "-4" or "-6" */
290
sig = get_signum(&arg[1]);
293
/* "-SIGNAL" option found. Remove it and bail out */
302
getopt32(argv, "^" OPTION_STRING "\0" "-1"/*at least one arg*/);
309
char path[sizeof("/proc/net/TCP6")];
311
strcpy(path, "/proc/net/");
312
if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
313
&& access(path, R_OK) == 0
316
scan_proc_net_or_maps(path, port);
320
xstat(*pp, &statbuf);
326
if (scan_recursive("/proc")) {
327
if (!(option_mask32 & OPT_SILENT))
329
return G.kill_failed;