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 //usage:#define fuser_trivial_usage
11 //usage: "[OPTIONS] FILE or PORT/PROTO"
12 //usage:#define fuser_full_usage "\n\n"
13 //usage: "Find processes which use FILEs or PORTs\n"
14 //usage: "\n -m Find processes which use same fs as FILEs"
15 //usage: "\n -4,-6 Search only IPv4/IPv6 space"
16 //usage: "\n -s Don't display PIDs"
17 //usage: "\n -k Kill found processes"
18 //usage: "\n -SIGNAL Signal to send (default: KILL)"
24 #define OPTION_STRING "mks64"
28 OPT_SILENT = (1 << 2),
33 typedef struct inode_list {
34 struct inode_list *next;
42 inode_list *inode_list_head;
46 #define G (*(struct globals*)&bb_common_bufsiz1)
47 #define INIT_G() do { \
49 G.killsig = SIGKILL; \
52 static void add_inode(const struct stat *st)
54 inode_list **curr = &G.inode_list_head;
57 if ((*curr)->dev == st->st_dev
58 && (*curr)->inode == st->st_ino
62 curr = &(*curr)->next;
65 *curr = xzalloc(sizeof(inode_list));
66 (*curr)->dev = st->st_dev;
67 (*curr)->inode = st->st_ino;
70 static smallint search_dev_inode(const struct stat *st)
72 inode_list *ilist = G.inode_list_head;
75 if (ilist->dev == st->st_dev) {
76 if (option_mask32 & OPT_MOUNT)
78 if (ilist->inode == st->st_ino)
93 static smallint scan_proc_net_or_maps(const char *path, unsigned port)
96 char line[MAX_LINE + 1], addr[68];
98 long long uint64_inode;
105 f = fopen_for_read(path);
109 if (G.recursion_depth == PROC_NET) {
112 /* find socket dev */
114 fd = socket(AF_INET, SOCK_DGRAM, 0);
120 fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
121 "%*x:%*x %*x:%*x %*x %*d %*d %llu";
125 fmt = "%*s %*s %*s %x:%x %llu";
131 while (fgets(line, MAX_LINE, f)) {
132 r = sscanf(line, fmt, fag, sag, &uint64_inode);
136 statbuf.st_ino = uint64_inode;
137 if (G.recursion_depth == PROC_NET) {
139 if (r == 8 && (option_mask32 & OPT_IP6))
141 if (r > 8 && (option_mask32 & OPT_IP4))
143 if (tmp_port == port)
146 if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
147 statbuf.st_dev = makedev(major, minor);
148 retval = search_dev_inode(&statbuf);
159 static smallint scan_recursive(const char *path)
162 struct dirent *d_ent;
173 while (!stop_scan && (d_ent = readdir(d)) != NULL) {
178 subpath = concat_subpath_file(path, d_ent->d_name);
180 continue; /* . or .. */
182 switch (G.recursion_depth) {
184 pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
187 /* "this PID doesn't use specified FILEs or PORT/PROTO": */
188 || scan_recursive(subpath) == 0
192 if (option_mask32 & OPT_KILL) {
193 if (kill(pid, G.killsig) != 0) {
194 bb_perror_msg("kill pid %s", d_ent->d_name);
198 if (!(option_mask32 & OPT_SILENT))
199 printf("%s ", d_ent->d_name);
206 "cwd" "\0" "exe" "\0"
207 "root" "\0" "fd" "\0"
208 "lib" "\0" "mmap" "\0"
229 stop_scan = scan_recursive(subpath);
234 stop_scan = scan_proc_net_or_maps(subpath, 0);
241 case PROC_SUBDIR_LINKS:
243 if (stat(subpath, &statbuf) < 0)
245 stop_scan = search_dev_inode(&statbuf);
258 int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
259 int fuser_main(int argc UNUSED_PARAM, char **argv)
265 /* Handle -SIGNAL. Oh my... */
273 if (arg[1] == '-' && arg[2] == '\0') /* "--" */
275 if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
276 continue; /* it's "-4" or "-6" */
277 sig = get_signum(&arg[1]);
280 /* "-SIGNAL" option found. Remove it and bail out */
289 opt_complementary = "-1"; /* at least one param */
290 getopt32(argv, OPTION_STRING);
297 char path[sizeof("/proc/net/TCP6")];
299 strcpy(path, "/proc/net/");
300 if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
301 && access(path, R_OK) == 0
304 scan_proc_net_or_maps(path, port);
308 xstat(*pp, &statbuf);
314 if (scan_recursive("/proc")) {
315 if (!(option_mask32 & OPT_SILENT))
317 return G.kill_failed;