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)"
21 #include "common_bufsiz.h"
25 #define OPTION_STRING "mks64"
29 OPT_SILENT = (1 << 2),
34 typedef struct inode_list {
35 struct inode_list *next;
43 inode_list *inode_list_head;
47 #define G (*(struct globals*)bb_common_bufsiz1)
48 #define INIT_G() do { \
49 setup_common_bufsiz(); \
51 G.killsig = SIGKILL; \
54 static void add_inode(const struct stat *st)
56 inode_list **curr = &G.inode_list_head;
59 if ((*curr)->dev == st->st_dev
60 && (*curr)->inode == st->st_ino
64 curr = &(*curr)->next;
67 *curr = xzalloc(sizeof(inode_list));
68 (*curr)->dev = st->st_dev;
69 (*curr)->inode = st->st_ino;
72 static smallint search_dev_inode(const struct stat *st)
74 inode_list *ilist = G.inode_list_head;
77 if (ilist->dev == st->st_dev) {
78 if (option_mask32 & OPT_MOUNT)
80 if (ilist->inode == st->st_ino)
95 static smallint scan_proc_net_or_maps(const char *path, unsigned port)
98 char line[MAX_LINE + 1], addr[68];
100 long long uint64_inode;
107 f = fopen_for_read(path);
111 if (G.recursion_depth == PROC_NET) {
114 /* find socket dev */
116 fd = socket(AF_INET, SOCK_DGRAM, 0);
122 fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
123 "%*x:%*x %*x:%*x %*x %*d %*d %llu";
127 fmt = "%*s %*s %*s %x:%x %llu";
133 while (fgets(line, MAX_LINE, f)) {
134 r = sscanf(line, fmt, fag, sag, &uint64_inode);
138 statbuf.st_ino = uint64_inode;
139 if (G.recursion_depth == PROC_NET) {
141 if (r == 8 && (option_mask32 & OPT_IP6))
143 if (r > 8 && (option_mask32 & OPT_IP4))
145 if (tmp_port == port)
148 if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
149 statbuf.st_dev = makedev(major, minor);
150 retval = search_dev_inode(&statbuf);
161 static smallint scan_recursive(const char *path)
164 struct dirent *d_ent;
175 while (!stop_scan && (d_ent = readdir(d)) != NULL) {
180 subpath = concat_subpath_file(path, d_ent->d_name);
182 continue; /* . or .. */
184 switch (G.recursion_depth) {
186 pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
189 /* "this PID doesn't use specified FILEs or PORT/PROTO": */
190 || scan_recursive(subpath) == 0
194 if (option_mask32 & OPT_KILL) {
195 if (kill(pid, G.killsig) != 0) {
196 bb_perror_msg("kill pid %s", d_ent->d_name);
200 if (!(option_mask32 & OPT_SILENT))
201 printf("%s ", d_ent->d_name);
208 "cwd" "\0" "exe" "\0"
209 "root" "\0" "fd" "\0"
210 "lib" "\0" "mmap" "\0"
231 stop_scan = scan_recursive(subpath);
236 stop_scan = scan_proc_net_or_maps(subpath, 0);
243 case PROC_SUBDIR_LINKS:
245 if (stat(subpath, &statbuf) < 0)
247 stop_scan = search_dev_inode(&statbuf);
260 int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
261 int fuser_main(int argc UNUSED_PARAM, char **argv)
267 /* Handle -SIGNAL. Oh my... */
275 if (arg[1] == '-' && arg[2] == '\0') /* "--" */
277 if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
278 continue; /* it's "-4" or "-6" */
279 sig = get_signum(&arg[1]);
282 /* "-SIGNAL" option found. Remove it and bail out */
291 opt_complementary = "-1"; /* at least one param */
292 getopt32(argv, OPTION_STRING);
299 char path[sizeof("/proc/net/TCP6")];
301 strcpy(path, "/proc/net/");
302 if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
303 && access(path, R_OK) == 0
306 scan_proc_net_or_maps(path, port);
310 xstat(*pp, &statbuf);
316 if (scan_recursive("/proc")) {
317 if (!(option_mask32 & OPT_SILENT))
319 return G.kill_failed;