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 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: "[OPTIONS] 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;