Annotation of /tags/mkinitrd-6_5_1/busybox/procps/fuser.c
Parent Directory | Revision Log
Revision 1123 -
(hide annotations)
(download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/procps/fuser.c
File MIME type: text/plain
File size: 6086 byte(s)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
Original Path: trunk/mkinitrd-magellan/busybox/procps/fuser.c
File MIME type: text/plain
File size: 6086 byte(s)
-updated to busybox-1.17.1
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * tiny fuser implementation | ||
4 | * | ||
5 | * Copyright 2004 Tony J. White | ||
6 | * | ||
7 | niro | 984 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
8 | niro | 532 | */ |
9 | |||
10 | niro | 816 | #include "libbb.h" |
11 | niro | 532 | |
12 | niro | 816 | #define MAX_LINE 255 |
13 | niro | 532 | |
14 | niro | 816 | #define OPTION_STRING "mks64" |
15 | enum { | ||
16 | OPT_MOUNT = (1 << 0), | ||
17 | OPT_KILL = (1 << 1), | ||
18 | OPT_SILENT = (1 << 2), | ||
19 | OPT_IP6 = (1 << 3), | ||
20 | OPT_IP4 = (1 << 4), | ||
21 | }; | ||
22 | niro | 532 | |
23 | typedef struct inode_list { | ||
24 | niro | 816 | struct inode_list *next; |
25 | niro | 532 | ino_t inode; |
26 | dev_t dev; | ||
27 | } inode_list; | ||
28 | |||
29 | typedef struct pid_list { | ||
30 | niro | 816 | struct pid_list *next; |
31 | niro | 532 | pid_t pid; |
32 | } pid_list; | ||
33 | |||
34 | niro | 1123 | |
35 | struct globals { | ||
36 | pid_list *pid_list_head; | ||
37 | inode_list *inode_list_head; | ||
38 | }; | ||
39 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
40 | #define INIT_G() do { } while (0) | ||
41 | |||
42 | |||
43 | static void add_pid(const pid_t pid) | ||
44 | niro | 532 | { |
45 | niro | 1123 | pid_list **curr = &G.pid_list_head; |
46 | |||
47 | while (*curr) { | ||
48 | if ((*curr)->pid == pid) | ||
49 | return; | ||
50 | curr = &(*curr)->next; | ||
51 | niro | 532 | } |
52 | |||
53 | niro | 1123 | *curr = xzalloc(sizeof(pid_list)); |
54 | (*curr)->pid = pid; | ||
55 | niro | 532 | } |
56 | |||
57 | niro | 1123 | static void add_inode(const struct stat *st) |
58 | niro | 532 | { |
59 | niro | 1123 | inode_list **curr = &G.inode_list_head; |
60 | niro | 532 | |
61 | niro | 1123 | while (*curr) { |
62 | if ((*curr)->dev == st->st_dev | ||
63 | && (*curr)->inode == st->st_ino | ||
64 | ) { | ||
65 | return; | ||
66 | } | ||
67 | curr = &(*curr)->next; | ||
68 | niro | 532 | } |
69 | |||
70 | niro | 1123 | *curr = xzalloc(sizeof(inode_list)); |
71 | (*curr)->dev = st->st_dev; | ||
72 | (*curr)->inode = st->st_ino; | ||
73 | niro | 532 | } |
74 | |||
75 | niro | 1123 | static void scan_proc_net(const char *path, unsigned port) |
76 | niro | 532 | { |
77 | niro | 1123 | char line[MAX_LINE + 1]; |
78 | niro | 816 | long long uint64_inode; |
79 | unsigned tmp_port; | ||
80 | niro | 532 | FILE *f; |
81 | niro | 1123 | struct stat st; |
82 | int fd; | ||
83 | niro | 532 | |
84 | niro | 1123 | /* find socket dev */ |
85 | st.st_dev = 0; | ||
86 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
87 | if (fd >= 0) { | ||
88 | fstat(fd, &st); | ||
89 | close(fd); | ||
90 | } | ||
91 | niro | 532 | |
92 | niro | 816 | f = fopen_for_read(path); |
93 | if (!f) | ||
94 | niro | 1123 | return; |
95 | niro | 816 | |
96 | while (fgets(line, MAX_LINE, f)) { | ||
97 | char addr[68]; | ||
98 | if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " | ||
99 | "%*x:%*x %*x %*d %*d %llu", | ||
100 | addr, &tmp_port, &uint64_inode) == 3 | ||
101 | ) { | ||
102 | int len = strlen(addr); | ||
103 | if (len == 8 && (option_mask32 & OPT_IP6)) | ||
104 | continue; | ||
105 | if (len > 8 && (option_mask32 & OPT_IP4)) | ||
106 | continue; | ||
107 | if (tmp_port == port) { | ||
108 | niro | 1123 | st.st_ino = uint64_inode; |
109 | add_inode(&st); | ||
110 | niro | 532 | } |
111 | } | ||
112 | } | ||
113 | fclose(f); | ||
114 | } | ||
115 | |||
116 | niro | 1123 | static int search_dev_inode(const struct stat *st) |
117 | niro | 532 | { |
118 | niro | 1123 | inode_list *ilist = G.inode_list_head; |
119 | |||
120 | niro | 816 | while (ilist) { |
121 | niro | 1123 | if (ilist->dev == st->st_dev) { |
122 | niro | 816 | if (option_mask32 & OPT_MOUNT) |
123 | return 1; | ||
124 | niro | 1123 | if (ilist->inode == st->st_ino) |
125 | niro | 816 | return 1; |
126 | } | ||
127 | ilist = ilist->next; | ||
128 | niro | 532 | } |
129 | return 0; | ||
130 | } | ||
131 | |||
132 | niro | 1123 | static void scan_pid_maps(const char *fname, pid_t pid) |
133 | niro | 532 | { |
134 | FILE *file; | ||
135 | niro | 816 | char line[MAX_LINE + 1]; |
136 | niro | 532 | int major, minor; |
137 | long long uint64_inode; | ||
138 | niro | 1123 | struct stat st; |
139 | niro | 532 | |
140 | niro | 816 | file = fopen_for_read(fname); |
141 | if (!file) | ||
142 | niro | 1123 | return; |
143 | |||
144 | niro | 816 | while (fgets(line, MAX_LINE, file)) { |
145 | if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) | ||
146 | continue; | ||
147 | niro | 1123 | st.st_ino = uint64_inode; |
148 | if (major == 0 && minor == 0 && st.st_ino == 0) | ||
149 | niro | 816 | continue; |
150 | niro | 1123 | st.st_dev = makedev(major, minor); |
151 | if (search_dev_inode(&st)) | ||
152 | add_pid(pid); | ||
153 | niro | 532 | } |
154 | fclose(file); | ||
155 | } | ||
156 | |||
157 | niro | 1123 | static void scan_link(const char *lname, pid_t pid) |
158 | niro | 532 | { |
159 | niro | 1123 | struct stat st; |
160 | niro | 532 | |
161 | niro | 1123 | if (stat(lname, &st) >= 0) { |
162 | if (search_dev_inode(&st)) | ||
163 | add_pid(pid); | ||
164 | } | ||
165 | niro | 532 | } |
166 | |||
167 | niro | 1123 | static void scan_dir_links(const char *dname, pid_t pid) |
168 | niro | 532 | { |
169 | DIR *d; | ||
170 | struct dirent *de; | ||
171 | char *lname; | ||
172 | |||
173 | niro | 816 | d = opendir(dname); |
174 | if (!d) | ||
175 | niro | 1123 | return; |
176 | |||
177 | niro | 816 | while ((de = readdir(d)) != NULL) { |
178 | lname = concat_subpath_file(dname, de->d_name); | ||
179 | if (lname == NULL) | ||
180 | continue; | ||
181 | niro | 1123 | scan_link(lname, pid); |
182 | niro | 816 | free(lname); |
183 | niro | 532 | } |
184 | niro | 816 | closedir(d); |
185 | niro | 532 | } |
186 | |||
187 | niro | 816 | /* NB: does chdir internally */ |
188 | niro | 1123 | static void scan_proc_pids(void) |
189 | niro | 532 | { |
190 | DIR *d; | ||
191 | struct dirent *de; | ||
192 | pid_t pid; | ||
193 | |||
194 | niro | 816 | xchdir("/proc"); |
195 | d = opendir("/proc"); | ||
196 | if (!d) | ||
197 | niro | 1123 | return; |
198 | niro | 816 | |
199 | while ((de = readdir(d)) != NULL) { | ||
200 | pid = (pid_t)bb_strtou(de->d_name, NULL, 10); | ||
201 | if (errno) | ||
202 | niro | 532 | continue; |
203 | niro | 816 | if (chdir(de->d_name) < 0) |
204 | continue; | ||
205 | niro | 1123 | scan_link("cwd", pid); |
206 | scan_link("exe", pid); | ||
207 | scan_link("root", pid); | ||
208 | |||
209 | scan_dir_links("fd", pid); | ||
210 | scan_dir_links("lib", pid); | ||
211 | scan_dir_links("mmap", pid); | ||
212 | |||
213 | scan_pid_maps("maps", pid); | ||
214 | niro | 816 | xchdir("/proc"); |
215 | niro | 532 | } |
216 | closedir(d); | ||
217 | } | ||
218 | |||
219 | niro | 816 | int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
220 | int fuser_main(int argc UNUSED_PARAM, char **argv) | ||
221 | niro | 532 | { |
222 | niro | 816 | pid_list *plist; |
223 | niro | 1123 | pid_t mypid; |
224 | niro | 816 | char **pp; |
225 | niro | 1123 | struct stat st; |
226 | niro | 816 | unsigned port; |
227 | int opt; | ||
228 | niro | 1123 | int exitcode; |
229 | niro | 816 | int killsig; |
230 | /* | ||
231 | niro | 1123 | fuser [OPTIONS] FILE or PORT/PROTO |
232 | niro | 816 | Find processes which use FILEs or PORTs |
233 | -m Find processes which use same fs as FILEs | ||
234 | -4 Search only IPv4 space | ||
235 | -6 Search only IPv6 space | ||
236 | niro | 1123 | -s Don't display PIDs |
237 | -k Kill found processes | ||
238 | -SIGNAL Signal to send (default: KILL) | ||
239 | niro | 816 | */ |
240 | /* Handle -SIGNAL. Oh my... */ | ||
241 | niro | 1123 | killsig = SIGKILL; /* yes, the default is not SIGTERM */ |
242 | niro | 816 | pp = argv; |
243 | while (*++pp) { | ||
244 | char *arg = *pp; | ||
245 | if (arg[0] != '-') | ||
246 | continue; | ||
247 | if (arg[1] == '-' && arg[2] == '\0') /* "--" */ | ||
248 | break; | ||
249 | if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') | ||
250 | continue; /* it's "-4" or "-6" */ | ||
251 | opt = get_signum(&arg[1]); | ||
252 | if (opt < 0) | ||
253 | continue; | ||
254 | /* "-SIGNAL" option found. Remove it and bail out */ | ||
255 | killsig = opt; | ||
256 | do { | ||
257 | pp[0] = arg = pp[1]; | ||
258 | pp++; | ||
259 | } while (arg); | ||
260 | break; | ||
261 | } | ||
262 | niro | 532 | |
263 | niro | 1123 | opt_complementary = "-1"; /* at least one param */ |
264 | niro | 816 | opt = getopt32(argv, OPTION_STRING); |
265 | argv += optind; | ||
266 | niro | 532 | |
267 | niro | 816 | pp = argv; |
268 | while (*pp) { | ||
269 | niro | 1123 | /* parse net arg */ |
270 | char path[20], tproto[5]; | ||
271 | if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) | ||
272 | goto file; | ||
273 | sprintf(path, "/proc/net/%s", tproto); | ||
274 | if (access(path, R_OK) != 0) { /* PORT/PROTO */ | ||
275 | scan_proc_net(path, port); | ||
276 | niro | 816 | } else { /* FILE */ |
277 | niro | 1123 | file: |
278 | xstat(*pp, &st); | ||
279 | add_inode(&st); | ||
280 | niro | 532 | } |
281 | niro | 816 | pp++; |
282 | niro | 532 | } |
283 | |||
284 | niro | 1123 | scan_proc_pids(); /* changes dir to "/proc" */ |
285 | niro | 816 | |
286 | niro | 1123 | mypid = getpid(); |
287 | plist = G.pid_list_head; | ||
288 | while (1) { | ||
289 | if (!plist) | ||
290 | return EXIT_FAILURE; | ||
291 | if (plist->pid != mypid) | ||
292 | break; | ||
293 | plist = plist->next; | ||
294 | niro | 532 | } |
295 | niro | 1123 | |
296 | exitcode = EXIT_SUCCESS; | ||
297 | do { | ||
298 | if (plist->pid != mypid) { | ||
299 | if (opt & OPT_KILL) { | ||
300 | if (kill(plist->pid, killsig) != 0) { | ||
301 | bb_perror_msg("kill pid %u", (unsigned)plist->pid); | ||
302 | exitcode = EXIT_FAILURE; | ||
303 | } | ||
304 | } | ||
305 | if (!(opt & OPT_SILENT)) { | ||
306 | printf("%u ", (unsigned)plist->pid); | ||
307 | } | ||
308 | } | ||
309 | plist = plist->next; | ||
310 | } while (plist); | ||
311 | |||
312 | if (!(opt & (OPT_SILENT))) { | ||
313 | bb_putchar('\n'); | ||
314 | } | ||
315 | |||
316 | return exitcode; | ||
317 | niro | 532 | } |