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"
15 //usage: "\n -m Find processes which use same fs as FILEs"
16 //usage: "\n -4,-6 Search only IPv4/IPv6 space"
17 //usage: "\n -s Don't display PIDs"
18 //usage: "\n -k Kill found processes"
19 //usage: "\n -SIGNAL Signal to send (default: KILL)"
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 { \
50 G.killsig = SIGKILL; \
53 static void add_inode(const struct stat *st)
55 inode_list **curr = &G.inode_list_head;
58 if ((*curr)->dev == st->st_dev
59 && (*curr)->inode == st->st_ino
63 curr = &(*curr)->next;
66 *curr = xzalloc(sizeof(inode_list));
67 (*curr)->dev = st->st_dev;
68 (*curr)->inode = st->st_ino;
71 static smallint search_dev_inode(const struct stat *st)
73 inode_list *ilist = G.inode_list_head;
76 if (ilist->dev == st->st_dev) {
77 if (option_mask32 & OPT_MOUNT)
79 if (ilist->inode == st->st_ino)
94 static smallint scan_proc_net_or_maps(const char *path, unsigned port)
97 char line[MAX_LINE + 1], addr[68];
99 long long uint64_inode;
106 f = fopen_for_read(path);
110 if (G.recursion_depth == PROC_NET) {
113 /* find socket dev */
115 fd = socket(AF_INET, SOCK_DGRAM, 0);
121 fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
122 "%*x:%*x %*x:%*x %*x %*d %*d %llu";
126 fmt = "%*s %*s %*s %x:%x %llu";
132 while (fgets(line, MAX_LINE, f)) {
133 r = sscanf(line, fmt, fag, sag, &uint64_inode);
137 statbuf.st_ino = uint64_inode;
138 if (G.recursion_depth == PROC_NET) {
140 if (r == 8 && (option_mask32 & OPT_IP6))
142 if (r > 8 && (option_mask32 & OPT_IP4))
144 if (tmp_port == port)
147 if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
148 statbuf.st_dev = makedev(major, minor);
149 retval = search_dev_inode(&statbuf);
160 static smallint scan_recursive(const char *path)
163 struct dirent *d_ent;
174 while (!stop_scan && (d_ent = readdir(d)) != NULL) {
179 subpath = concat_subpath_file(path, d_ent->d_name);
181 continue; /* . or .. */
183 switch (G.recursion_depth) {
185 pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
188 /* "this PID doesn't use specified FILEs or PORT/PROTO": */
189 || scan_recursive(subpath) == 0
193 if (option_mask32 & OPT_KILL) {
194 if (kill(pid, G.killsig) != 0) {
195 bb_perror_msg("kill pid %s", d_ent->d_name);
199 if (!(option_mask32 & OPT_SILENT))
200 printf("%s ", d_ent->d_name);
207 "cwd" "\0" "exe" "\0"
208 "root" "\0" "fd" "\0"
209 "lib" "\0" "mmap" "\0"
230 stop_scan = scan_recursive(subpath);
235 stop_scan = scan_proc_net_or_maps(subpath, 0);
242 case PROC_SUBDIR_LINKS:
244 if (stat(subpath, &statbuf) < 0)
246 stop_scan = search_dev_inode(&statbuf);
259 int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
260 int fuser_main(int argc UNUSED_PARAM, char **argv)
266 /* Handle -SIGNAL. Oh my... */
274 if (arg[1] == '-' && arg[2] == '\0') /* "--" */
276 if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
277 continue; /* it's "-4" or "-6" */
278 sig = get_signum(&arg[1]);
281 /* "-SIGNAL" option found. Remove it and bail out */
290 opt_complementary = "-1"; /* at least one param */
291 getopt32(argv, OPTION_STRING);
298 char path[sizeof("/proc/net/TCP6")];
300 strcpy(path, "/proc/net/");
301 if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
302 && access(path, R_OK) != 0
305 scan_proc_net_or_maps(path, port);
309 xstat(*pp, &statbuf);
315 if (scan_recursive("/proc")) {
316 if (!(option_mask32 & OPT_SILENT))
318 return G.kill_failed;