source: MondoRescue/branches/3.3/mindi-busybox/procps/fuser.c@ 3902

Last change on this file since 3902 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 6.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * tiny fuser implementation
4 *
5 * Copyright 2004 Tony J. White
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9
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)"
19
20#include "libbb.h"
21#include "common_bufsiz.h"
22
23#define MAX_LINE 255
24
25#define OPTION_STRING "mks64"
26enum {
27 OPT_MOUNT = (1 << 0),
28 OPT_KILL = (1 << 1),
29 OPT_SILENT = (1 << 2),
30 OPT_IP6 = (1 << 3),
31 OPT_IP4 = (1 << 4),
32};
33
34typedef struct inode_list {
35 struct inode_list *next;
36 ino_t inode;
37 dev_t dev;
38} inode_list;
39
40struct globals {
41 int recursion_depth;
42 pid_t mypid;
43 inode_list *inode_list_head;
44 smallint kill_failed;
45 int killsig;
46} FIX_ALIASING;
47#define G (*(struct globals*)bb_common_bufsiz1)
48#define INIT_G() do { \
49 setup_common_bufsiz(); \
50 G.mypid = getpid(); \
51 G.killsig = SIGKILL; \
52} while (0)
53
54static void add_inode(const struct stat *st)
55{
56 inode_list **curr = &G.inode_list_head;
57
58 while (*curr) {
59 if ((*curr)->dev == st->st_dev
60 && (*curr)->inode == st->st_ino
61 ) {
62 return;
63 }
64 curr = &(*curr)->next;
65 }
66
67 *curr = xzalloc(sizeof(inode_list));
68 (*curr)->dev = st->st_dev;
69 (*curr)->inode = st->st_ino;
70}
71
72static smallint search_dev_inode(const struct stat *st)
73{
74 inode_list *ilist = G.inode_list_head;
75
76 while (ilist) {
77 if (ilist->dev == st->st_dev) {
78 if (option_mask32 & OPT_MOUNT)
79 return 1;
80 if (ilist->inode == st->st_ino)
81 return 1;
82 }
83 ilist = ilist->next;
84 }
85 return 0;
86}
87
88enum {
89 PROC_NET = 0,
90 PROC_DIR,
91 PROC_DIR_LINKS,
92 PROC_SUBDIR_LINKS,
93};
94
95static smallint scan_proc_net_or_maps(const char *path, unsigned port)
96{
97 FILE *f;
98 char line[MAX_LINE + 1], addr[68];
99 int major, minor, r;
100 long long uint64_inode;
101 unsigned tmp_port;
102 smallint retval;
103 struct stat statbuf;
104 const char *fmt;
105 void *fag, *sag;
106
107 f = fopen_for_read(path);
108 if (!f)
109 return 0;
110
111 if (G.recursion_depth == PROC_NET) {
112 int fd;
113
114 /* find socket dev */
115 statbuf.st_dev = 0;
116 fd = socket(AF_INET, SOCK_DGRAM, 0);
117 if (fd >= 0) {
118 fstat(fd, &statbuf);
119 close(fd);
120 }
121
122 fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x "
123 "%*x:%*x %*x:%*x %*x %*d %*d %llu";
124 fag = addr;
125 sag = &tmp_port;
126 } else {
127 fmt = "%*s %*s %*s %x:%x %llu";
128 fag = &major;
129 sag = &minor;
130 }
131
132 retval = 0;
133 while (fgets(line, MAX_LINE, f)) {
134 r = sscanf(line, fmt, fag, sag, &uint64_inode);
135 if (r != 3)
136 continue;
137
138 statbuf.st_ino = uint64_inode;
139 if (G.recursion_depth == PROC_NET) {
140 r = strlen(addr);
141 if (r == 8 && (option_mask32 & OPT_IP6))
142 continue;
143 if (r > 8 && (option_mask32 & OPT_IP4))
144 continue;
145 if (tmp_port == port)
146 add_inode(&statbuf);
147 } else {
148 if (major != 0 && minor != 0 && statbuf.st_ino != 0) {
149 statbuf.st_dev = makedev(major, minor);
150 retval = search_dev_inode(&statbuf);
151 if (retval)
152 break;
153 }
154 }
155 }
156 fclose(f);
157
158 return retval;
159}
160
161static smallint scan_recursive(const char *path)
162{
163 DIR *d;
164 struct dirent *d_ent;
165 smallint stop_scan;
166 smallint retval;
167
168 d = opendir(path);
169 if (d == NULL)
170 return 0;
171
172 G.recursion_depth++;
173 retval = 0;
174 stop_scan = 0;
175 while (!stop_scan && (d_ent = readdir(d)) != NULL) {
176 struct stat statbuf;
177 pid_t pid;
178 char *subpath;
179
180 subpath = concat_subpath_file(path, d_ent->d_name);
181 if (subpath == NULL)
182 continue; /* . or .. */
183
184 switch (G.recursion_depth) {
185 case PROC_DIR:
186 pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10);
187 if (errno != 0
188 || pid == G.mypid
189 /* "this PID doesn't use specified FILEs or PORT/PROTO": */
190 || scan_recursive(subpath) == 0
191 ) {
192 break;
193 }
194 if (option_mask32 & OPT_KILL) {
195 if (kill(pid, G.killsig) != 0) {
196 bb_perror_msg("kill pid %s", d_ent->d_name);
197 G.kill_failed = 1;
198 }
199 }
200 if (!(option_mask32 & OPT_SILENT))
201 printf("%s ", d_ent->d_name);
202 retval = 1;
203 break;
204
205 case PROC_DIR_LINKS:
206 switch (
207 index_in_substrings(
208 "cwd" "\0" "exe" "\0"
209 "root" "\0" "fd" "\0"
210 "lib" "\0" "mmap" "\0"
211 "maps" "\0",
212 d_ent->d_name
213 )
214 ) {
215 enum {
216 CWD_LINK,
217 EXE_LINK,
218 ROOT_LINK,
219 FD_DIR_LINKS,
220 LIB_DIR_LINKS,
221 MMAP_DIR_LINKS,
222 MAPS,
223 };
224 case CWD_LINK:
225 case EXE_LINK:
226 case ROOT_LINK:
227 goto scan_link;
228 case FD_DIR_LINKS:
229 case LIB_DIR_LINKS:
230 case MMAP_DIR_LINKS:
231 stop_scan = scan_recursive(subpath);
232 if (stop_scan)
233 retval = stop_scan;
234 break;
235 case MAPS:
236 stop_scan = scan_proc_net_or_maps(subpath, 0);
237 if (stop_scan)
238 retval = stop_scan;
239 default:
240 break;
241 }
242 break;
243 case PROC_SUBDIR_LINKS:
244 scan_link:
245 if (stat(subpath, &statbuf) < 0)
246 break;
247 stop_scan = search_dev_inode(&statbuf);
248 if (stop_scan)
249 retval = stop_scan;
250 default:
251 break;
252 }
253 free(subpath);
254 }
255 closedir(d);
256 G.recursion_depth--;
257 return retval;
258}
259
260int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
261int fuser_main(int argc UNUSED_PARAM, char **argv)
262{
263 char **pp;
264
265 INIT_G();
266
267 /* Handle -SIGNAL. Oh my... */
268 pp = argv;
269 while (*++pp) {
270 int sig;
271 char *arg = *pp;
272
273 if (arg[0] != '-')
274 continue;
275 if (arg[1] == '-' && arg[2] == '\0') /* "--" */
276 break;
277 if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
278 continue; /* it's "-4" or "-6" */
279 sig = get_signum(&arg[1]);
280 if (sig < 0)
281 continue;
282 /* "-SIGNAL" option found. Remove it and bail out */
283 G.killsig = sig;
284 do {
285 pp[0] = arg = pp[1];
286 pp++;
287 } while (arg);
288 break;
289 }
290
291 opt_complementary = "-1"; /* at least one param */
292 getopt32(argv, OPTION_STRING);
293 argv += optind;
294
295 pp = argv;
296 while (*pp) {
297 /* parse net arg */
298 unsigned port;
299 char path[sizeof("/proc/net/TCP6")];
300
301 strcpy(path, "/proc/net/");
302 if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
303 && access(path, R_OK) == 0
304 ) {
305 /* PORT/PROTO */
306 scan_proc_net_or_maps(path, port);
307 } else {
308 /* FILE */
309 struct stat statbuf;
310 xstat(*pp, &statbuf);
311 add_inode(&statbuf);
312 }
313 pp++;
314 }
315
316 if (scan_recursive("/proc")) {
317 if (!(option_mask32 & OPT_SILENT))
318 bb_putchar('\n');
319 return G.kill_failed;
320 }
321
322 return EXIT_FAILURE;
323}
Note: See TracBrowser for help on using the repository browser.