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
;