diff options
author | Maksym Kryzhanovskyy <xmaks@email.cz> | 2011-05-23 03:39:48 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-23 03:39:48 +0200 |
commit | eeed2306fceacf2baea77712b309b4fa40e671b6 (patch) | |
tree | 0341610654d6c7329a9541d9c5541a3db77b6df2 | |
parent | e6df7e261ec430de6f9e9cd9a0eb0d997b553d68 (diff) | |
download | busybox-w32-eeed2306fceacf2baea77712b309b4fa40e671b6.tar.gz busybox-w32-eeed2306fceacf2baea77712b309b4fa40e671b6.tar.bz2 busybox-w32-eeed2306fceacf2baea77712b309b4fa40e671b6.zip |
fuser: code shrink
function old new delta
scan_proc_net_or_maps - 427 +427
scan_recursive - 380 +380
search_dev_inode 74 71 -3
add_pid 39 - -39
scan_link 46 - -46
scan_dir_links 76 - -76
scan_pid_maps 222 - -222
fuser_main 871 297 -574
------------------------------------------------------------------------------
(add/remove: 2/4 grow/shrink: 0/2 up/down: 807/-960) Total: -153 bytes
Signed-off-by: Maksym Kryzhanovskyy <xmaks@email.cz>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | procps/fuser.c | 386 |
1 files changed, 190 insertions, 196 deletions
diff --git a/procps/fuser.c b/procps/fuser.c index 7837ff883..2a7c3106e 100644 --- a/procps/fuser.c +++ b/procps/fuser.c | |||
@@ -37,33 +37,18 @@ typedef struct inode_list { | |||
37 | dev_t dev; | 37 | dev_t dev; |
38 | } inode_list; | 38 | } inode_list; |
39 | 39 | ||
40 | typedef struct pid_list { | ||
41 | struct pid_list *next; | ||
42 | pid_t pid; | ||
43 | } pid_list; | ||
44 | |||
45 | |||
46 | struct globals { | 40 | struct globals { |
47 | pid_list *pid_list_head; | 41 | int recursion_depth; |
42 | pid_t mypid; | ||
48 | inode_list *inode_list_head; | 43 | inode_list *inode_list_head; |
44 | smallint kill_failed; | ||
45 | int killsig; | ||
49 | } FIX_ALIASING; | 46 | } FIX_ALIASING; |
50 | #define G (*(struct globals*)&bb_common_bufsiz1) | 47 | #define G (*(struct globals*)&bb_common_bufsiz1) |
51 | #define INIT_G() do { } while (0) | 48 | #define INIT_G() do { \ |
52 | 49 | G.mypid = getpid(); \ | |
53 | 50 | G.killsig = SIGKILL; \ | |
54 | static void add_pid(const pid_t pid) | 51 | } while (0) |
55 | { | ||
56 | pid_list **curr = &G.pid_list_head; | ||
57 | |||
58 | while (*curr) { | ||
59 | if ((*curr)->pid == pid) | ||
60 | return; | ||
61 | curr = &(*curr)->next; | ||
62 | } | ||
63 | |||
64 | *curr = xzalloc(sizeof(pid_list)); | ||
65 | (*curr)->pid = pid; | ||
66 | } | ||
67 | 52 | ||
68 | static void add_inode(const struct stat *st) | 53 | static void add_inode(const struct stat *st) |
69 | { | 54 | { |
@@ -83,48 +68,7 @@ static void add_inode(const struct stat *st) | |||
83 | (*curr)->inode = st->st_ino; | 68 | (*curr)->inode = st->st_ino; |
84 | } | 69 | } |
85 | 70 | ||
86 | static void scan_proc_net(const char *path, unsigned port) | 71 | static smallint search_dev_inode(const struct stat *st) |
87 | { | ||
88 | char line[MAX_LINE + 1]; | ||
89 | long long uint64_inode; | ||
90 | unsigned tmp_port; | ||
91 | FILE *f; | ||
92 | struct stat st; | ||
93 | int fd; | ||
94 | |||
95 | /* find socket dev */ | ||
96 | st.st_dev = 0; | ||
97 | fd = socket(AF_INET, SOCK_DGRAM, 0); | ||
98 | if (fd >= 0) { | ||
99 | fstat(fd, &st); | ||
100 | close(fd); | ||
101 | } | ||
102 | |||
103 | f = fopen_for_read(path); | ||
104 | if (!f) | ||
105 | return; | ||
106 | |||
107 | while (fgets(line, MAX_LINE, f)) { | ||
108 | char addr[68]; | ||
109 | if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " | ||
110 | "%*x:%*x %*x %*d %*d %llu", | ||
111 | addr, &tmp_port, &uint64_inode) == 3 | ||
112 | ) { | ||
113 | int len = strlen(addr); | ||
114 | if (len == 8 && (option_mask32 & OPT_IP6)) | ||
115 | continue; | ||
116 | if (len > 8 && (option_mask32 & OPT_IP4)) | ||
117 | continue; | ||
118 | if (tmp_port == port) { | ||
119 | st.st_ino = uint64_inode; | ||
120 | add_inode(&st); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | fclose(f); | ||
125 | } | ||
126 | |||
127 | static int search_dev_inode(const struct stat *st) | ||
128 | { | 72 | { |
129 | inode_list *ilist = G.inode_list_head; | 73 | inode_list *ilist = G.inode_list_head; |
130 | 74 | ||
@@ -140,130 +84,202 @@ static int search_dev_inode(const struct stat *st) | |||
140 | return 0; | 84 | return 0; |
141 | } | 85 | } |
142 | 86 | ||
143 | static void scan_pid_maps(const char *fname, pid_t pid) | 87 | enum { |
88 | PROC_NET = 0, | ||
89 | PROC_DIR, | ||
90 | PROC_DIR_LINKS, | ||
91 | PROC_SUBDIR_LINKS, | ||
92 | }; | ||
93 | |||
94 | static smallint scan_proc_net_or_maps(const char *path, unsigned port) | ||
144 | { | 95 | { |
145 | FILE *file; | 96 | FILE *f; |
146 | char line[MAX_LINE + 1]; | 97 | char line[MAX_LINE + 1], addr[68]; |
147 | int major, minor; | 98 | int major, minor, r; |
148 | long long uint64_inode; | 99 | long long uint64_inode; |
149 | struct stat st; | 100 | unsigned tmp_port; |
101 | smallint retval; | ||
102 | struct stat statbuf; | ||
103 | const char *fmt; | ||
104 | void *fag, *sag; | ||
150 | 105 | ||
151 | file = fopen_for_read(fname); | 106 | f = fopen_for_read(path); |
152 | if (!file) | 107 | if (!f) |
153 | return; | 108 | return 0; |
154 | 109 | ||
155 | while (fgets(line, MAX_LINE, file)) { | 110 | if (G.recursion_depth == PROC_NET) { |
156 | if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) | 111 | int fd; |
157 | continue; | ||
158 | st.st_ino = uint64_inode; | ||
159 | if (major == 0 && minor == 0 && st.st_ino == 0) | ||
160 | continue; | ||
161 | st.st_dev = makedev(major, minor); | ||
162 | if (search_dev_inode(&st)) | ||
163 | add_pid(pid); | ||
164 | } | ||
165 | fclose(file); | ||
166 | } | ||
167 | 112 | ||
168 | static void scan_link(const char *lname, pid_t pid) | 113 | /* find socket dev */ |
169 | { | 114 | statbuf.st_dev = 0; |
170 | struct stat st; | 115 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
116 | if (fd >= 0) { | ||
117 | fstat(fd, &statbuf); | ||
118 | close(fd); | ||
119 | } | ||
171 | 120 | ||
172 | if (stat(lname, &st) >= 0) { | 121 | fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x " |
173 | if (search_dev_inode(&st)) | 122 | "%*x:%*x %*x:%*x %*x %*d %*d %llu"; |
174 | add_pid(pid); | 123 | fag = addr; |
124 | sag = &tmp_port; | ||
125 | } else { | ||
126 | fmt = "%*s %*s %*s %x:%x %llu"; | ||
127 | fag = &major; | ||
128 | sag = &minor; | ||
175 | } | 129 | } |
176 | } | ||
177 | |||
178 | static void scan_dir_links(const char *dname, pid_t pid) | ||
179 | { | ||
180 | DIR *d; | ||
181 | struct dirent *de; | ||
182 | char *lname; | ||
183 | |||
184 | d = opendir(dname); | ||
185 | if (!d) | ||
186 | return; | ||
187 | 130 | ||
188 | while ((de = readdir(d)) != NULL) { | 131 | retval = 0; |
189 | lname = concat_subpath_file(dname, de->d_name); | 132 | while (fgets(line, MAX_LINE, f)) { |
190 | if (lname == NULL) | 133 | r = sscanf(line, fmt, fag, sag, &uint64_inode); |
134 | if (r != 3) | ||
191 | continue; | 135 | continue; |
192 | scan_link(lname, pid); | 136 | |
193 | free(lname); | 137 | statbuf.st_ino = uint64_inode; |
138 | if (G.recursion_depth == PROC_NET) { | ||
139 | r = strlen(addr); | ||
140 | if (r == 8 && (option_mask32 & OPT_IP6)) | ||
141 | continue; | ||
142 | if (r > 8 && (option_mask32 & OPT_IP4)) | ||
143 | continue; | ||
144 | if (tmp_port == port) | ||
145 | add_inode(&statbuf); | ||
146 | } else { | ||
147 | if (major != 0 && minor != 0 && statbuf.st_ino != 0) { | ||
148 | statbuf.st_dev = makedev(major, minor); | ||
149 | retval = search_dev_inode(&statbuf); | ||
150 | if (retval) | ||
151 | break; | ||
152 | } | ||
153 | } | ||
194 | } | 154 | } |
195 | closedir(d); | 155 | fclose(f); |
156 | |||
157 | return retval; | ||
196 | } | 158 | } |
197 | 159 | ||
198 | /* NB: does chdir internally */ | 160 | static smallint scan_recursive(const char *path) |
199 | static void scan_proc_pids(void) | ||
200 | { | 161 | { |
201 | DIR *d; | 162 | DIR *d; |
202 | struct dirent *de; | 163 | struct dirent *d_ent; |
203 | pid_t pid; | 164 | smallint stop_scan; |
204 | 165 | smallint retval; | |
205 | xchdir("/proc"); | 166 | |
206 | d = opendir("/proc"); | 167 | d = opendir(path); |
207 | if (!d) | 168 | if (d == NULL) |
208 | return; | 169 | return 0; |
209 | 170 | ||
210 | while ((de = readdir(d)) != NULL) { | 171 | G.recursion_depth++; |
211 | pid = (pid_t)bb_strtou(de->d_name, NULL, 10); | 172 | retval = 0; |
212 | if (errno) | 173 | stop_scan = 0; |
213 | continue; | 174 | while (!stop_scan && (d_ent = readdir(d)) != NULL) { |
214 | if (chdir(de->d_name) < 0) | 175 | struct stat statbuf; |
215 | continue; | 176 | pid_t pid; |
216 | scan_link("cwd", pid); | 177 | char *subpath; |
217 | scan_link("exe", pid); | 178 | |
218 | scan_link("root", pid); | 179 | subpath = concat_subpath_file(path, d_ent->d_name); |
219 | 180 | if (subpath == NULL) | |
220 | scan_dir_links("fd", pid); | 181 | continue; /* . or .. */ |
221 | scan_dir_links("lib", pid); | 182 | |
222 | scan_dir_links("mmap", pid); | 183 | switch (G.recursion_depth) { |
184 | case PROC_DIR: | ||
185 | pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10); | ||
186 | if (errno != 0 | ||
187 | || pid == G.mypid | ||
188 | /* "this PID doesn't use specified FILEs or PORT/PROTO": */ | ||
189 | || scan_recursive(subpath) == 0 | ||
190 | ) { | ||
191 | break; | ||
192 | } | ||
193 | if (option_mask32 & OPT_KILL) { | ||
194 | if (kill(pid, G.killsig) != 0) { | ||
195 | bb_perror_msg("kill pid %s", d_ent->d_name); | ||
196 | G.kill_failed = 1; | ||
197 | } | ||
198 | } | ||
199 | if (!(option_mask32 & OPT_SILENT)) | ||
200 | printf("%s ", d_ent->d_name); | ||
201 | retval = 1; | ||
202 | break; | ||
223 | 203 | ||
224 | scan_pid_maps("maps", pid); | 204 | case PROC_DIR_LINKS: |
225 | xchdir("/proc"); | 205 | switch ( |
206 | index_in_substrings( | ||
207 | "cwd" "\0" "exe" "\0" | ||
208 | "root" "\0" "fd" "\0" | ||
209 | "lib" "\0" "mmap" "\0" | ||
210 | "maps" "\0", | ||
211 | d_ent->d_name | ||
212 | ) | ||
213 | ) { | ||
214 | enum { | ||
215 | CWD_LINK, | ||
216 | EXE_LINK, | ||
217 | ROOT_LINK, | ||
218 | FD_DIR_LINKS, | ||
219 | LIB_DIR_LINKS, | ||
220 | MMAP_DIR_LINKS, | ||
221 | MAPS, | ||
222 | }; | ||
223 | case CWD_LINK: | ||
224 | case EXE_LINK: | ||
225 | case ROOT_LINK: | ||
226 | goto scan_link; | ||
227 | case FD_DIR_LINKS: | ||
228 | case LIB_DIR_LINKS: | ||
229 | case MMAP_DIR_LINKS: | ||
230 | stop_scan = scan_recursive(subpath); | ||
231 | if (stop_scan) | ||
232 | retval = stop_scan; | ||
233 | break; | ||
234 | case MAPS: | ||
235 | stop_scan = scan_proc_net_or_maps(subpath, 0); | ||
236 | if (stop_scan) | ||
237 | retval = stop_scan; | ||
238 | default: | ||
239 | break; | ||
240 | } | ||
241 | break; | ||
242 | case PROC_SUBDIR_LINKS: | ||
243 | scan_link: | ||
244 | if (stat(subpath, &statbuf) < 0) | ||
245 | break; | ||
246 | stop_scan = search_dev_inode(&statbuf); | ||
247 | if (stop_scan) | ||
248 | retval = stop_scan; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | free(subpath); | ||
226 | } | 253 | } |
227 | closedir(d); | 254 | closedir(d); |
255 | G.recursion_depth--; | ||
256 | return retval; | ||
228 | } | 257 | } |
229 | 258 | ||
230 | int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 259 | int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
231 | int fuser_main(int argc UNUSED_PARAM, char **argv) | 260 | int fuser_main(int argc UNUSED_PARAM, char **argv) |
232 | { | 261 | { |
233 | pid_list *plist; | ||
234 | pid_t mypid; | ||
235 | char **pp; | 262 | char **pp; |
236 | struct stat st; | 263 | |
237 | unsigned port; | 264 | INIT_G(); |
238 | int opt; | 265 | |
239 | int exitcode; | ||
240 | int killsig; | ||
241 | /* | ||
242 | fuser [OPTIONS] FILE or PORT/PROTO | ||
243 | Find processes which use FILEs or PORTs | ||
244 | -m Find processes which use same fs as FILEs | ||
245 | -4 Search only IPv4 space | ||
246 | -6 Search only IPv6 space | ||
247 | -s Don't display PIDs | ||
248 | -k Kill found processes | ||
249 | -SIGNAL Signal to send (default: KILL) | ||
250 | */ | ||
251 | /* Handle -SIGNAL. Oh my... */ | 266 | /* Handle -SIGNAL. Oh my... */ |
252 | killsig = SIGKILL; /* yes, the default is not SIGTERM */ | ||
253 | pp = argv; | 267 | pp = argv; |
254 | while (*++pp) { | 268 | while (*++pp) { |
269 | int sig; | ||
255 | char *arg = *pp; | 270 | char *arg = *pp; |
271 | |||
256 | if (arg[0] != '-') | 272 | if (arg[0] != '-') |
257 | continue; | 273 | continue; |
258 | if (arg[1] == '-' && arg[2] == '\0') /* "--" */ | 274 | if (arg[1] == '-' && arg[2] == '\0') /* "--" */ |
259 | break; | 275 | break; |
260 | if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') | 276 | if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') |
261 | continue; /* it's "-4" or "-6" */ | 277 | continue; /* it's "-4" or "-6" */ |
262 | opt = get_signum(&arg[1]); | 278 | sig = get_signum(&arg[1]); |
263 | if (opt < 0) | 279 | if (sig < 0) |
264 | continue; | 280 | continue; |
265 | /* "-SIGNAL" option found. Remove it and bail out */ | 281 | /* "-SIGNAL" option found. Remove it and bail out */ |
266 | killsig = opt; | 282 | G.killsig = sig; |
267 | do { | 283 | do { |
268 | pp[0] = arg = pp[1]; | 284 | pp[0] = arg = pp[1]; |
269 | pp++; | 285 | pp++; |
@@ -272,57 +288,35 @@ Find processes which use FILEs or PORTs | |||
272 | } | 288 | } |
273 | 289 | ||
274 | opt_complementary = "-1"; /* at least one param */ | 290 | opt_complementary = "-1"; /* at least one param */ |
275 | opt = getopt32(argv, OPTION_STRING); | 291 | getopt32(argv, OPTION_STRING); |
276 | argv += optind; | 292 | argv += optind; |
277 | 293 | ||
278 | pp = argv; | 294 | pp = argv; |
279 | while (*pp) { | 295 | while (*pp) { |
280 | /* parse net arg */ | 296 | /* parse net arg */ |
281 | char path[20], tproto[5]; | 297 | unsigned port; |
282 | if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) | 298 | char path[sizeof("/proc/net/TCP6")]; |
283 | goto file; | 299 | |
284 | sprintf(path, "/proc/net/%s", tproto); | 300 | strcpy(path, "/proc/net/"); |
285 | if (access(path, R_OK) != 0) { /* PORT/PROTO */ | 301 | if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2 |
286 | scan_proc_net(path, port); | 302 | && access(path, R_OK) != 0 |
287 | } else { /* FILE */ | 303 | ) { |
288 | file: | 304 | /* PORT/PROTO */ |
289 | xstat(*pp, &st); | 305 | scan_proc_net_or_maps(path, port); |
290 | add_inode(&st); | 306 | } else { |
307 | /* FILE */ | ||
308 | struct stat statbuf; | ||
309 | xstat(*pp, &statbuf); | ||
310 | add_inode(&statbuf); | ||
291 | } | 311 | } |
292 | pp++; | 312 | pp++; |
293 | } | 313 | } |
294 | 314 | ||
295 | scan_proc_pids(); /* changes dir to "/proc" */ | 315 | if (scan_recursive("/proc")) { |
296 | 316 | if (!(option_mask32 & OPT_SILENT)) | |
297 | mypid = getpid(); | 317 | bb_putchar('\n'); |
298 | plist = G.pid_list_head; | 318 | return G.kill_failed; |
299 | while (1) { | ||
300 | if (!plist) | ||
301 | return EXIT_FAILURE; | ||
302 | if (plist->pid != mypid) | ||
303 | break; | ||
304 | plist = plist->next; | ||
305 | } | ||
306 | |||
307 | exitcode = EXIT_SUCCESS; | ||
308 | do { | ||
309 | if (plist->pid != mypid) { | ||
310 | if (opt & OPT_KILL) { | ||
311 | if (kill(plist->pid, killsig) != 0) { | ||
312 | bb_perror_msg("kill pid %u", (unsigned)plist->pid); | ||
313 | exitcode = EXIT_FAILURE; | ||
314 | } | ||
315 | } | ||
316 | if (!(opt & OPT_SILENT)) { | ||
317 | printf("%u ", (unsigned)plist->pid); | ||
318 | } | ||
319 | } | ||
320 | plist = plist->next; | ||
321 | } while (plist); | ||
322 | |||
323 | if (!(opt & (OPT_SILENT))) { | ||
324 | bb_putchar('\n'); | ||
325 | } | 319 | } |
326 | 320 | ||
327 | return exitcode; | 321 | return EXIT_FAILURE; |
328 | } | 322 | } |