source: MondoRescue/branches/stable/mindi-busybox/procps/fuser.c @ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

File size: 8.2 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * tiny fuser implementation
4 *
5 * Copyright 2004 Tony J. White
6 *
7 * May be distributed under the conditions of the
8 * GNU Library General Public License
9 */
10
11#include "busybox.h"
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <limits.h>
17#include <dirent.h>
18#include <signal.h>
19#include <sys/types.h>
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <sys/socket.h>
23#include <sys/sysmacros.h>
24
25#define FUSER_PROC_DIR "/proc"
26#define FUSER_MAX_LINE 255
27
28#define FUSER_OPT_MOUNT  1
29#define FUSER_OPT_KILL   2
30#define FUSER_OPT_SILENT 4
31#define FUSER_OPT_IP6    8
32#define FUSER_OPT_IP4    16
33
34typedef struct inode_list {
35    ino_t inode;
36    dev_t dev;
37    struct inode_list *next;
38} inode_list;
39
40typedef struct pid_list {
41    pid_t pid;
42    struct pid_list *next;
43} pid_list;
44
45static int fuser_option(char *option)
46{
47    int opt = 0;
48
49    if(!(strlen(option))) return 0;
50    if(option[0] != '-') return 0;
51    ++option;
52    while(*option != '\0') {
53        if(*option == 'm') opt |= FUSER_OPT_MOUNT;
54        else if(*option == 'k') opt |= FUSER_OPT_KILL;
55        else if(*option == 's') opt |= FUSER_OPT_SILENT;
56        else if(*option == '6') opt |= FUSER_OPT_IP6;
57        else if(*option == '4') opt |= FUSER_OPT_IP4;
58        else {
59            bb_error_msg_and_die(
60                "Unsupported option '%c'", *option);
61        }
62        ++option;
63    }
64    return opt;
65}
66
67static int fuser_file_to_dev_inode(const char *filename,
68     dev_t *dev, ino_t *inode)
69{
70    struct stat f_stat;
71    if((stat(filename, &f_stat)) < 0) return 0;
72    *inode = f_stat.st_ino;
73    *dev = f_stat.st_dev;
74    return 1;
75}
76
77static int fuser_find_socket_dev(dev_t *dev)
78{
79    int fd = socket(PF_INET, SOCK_DGRAM,0);
80    struct stat buf;
81
82    if (fd >= 0 && (fstat(fd, &buf)) == 0) {
83        *dev =  buf.st_dev;
84        close(fd);
85        return 1;
86    }
87    return 0;
88}
89
90static int fuser_parse_net_arg(const char *filename,
91    const char **proto, int *port)
92{
93    char path[sizeof(FUSER_PROC_DIR)+12], tproto[5];
94
95    if((sscanf(filename, "%d/%4s", port, tproto)) != 2) return 0;
96    sprintf(path, "%s/net/%s", FUSER_PROC_DIR, tproto);
97    if((access(path, R_OK)) != 0) return 0;
98    *proto = bb_xstrdup(tproto);
99    return 1;
100}
101
102static int fuser_add_pid(pid_list *plist, pid_t pid)
103{
104    pid_list *curr = NULL, *last = NULL;
105
106    if(plist->pid == 0) plist->pid = pid;
107    curr = plist;
108    while(curr != NULL) {
109        if(curr->pid == pid) return 1;
110        last = curr;
111        curr = curr->next;
112    }
113    curr = xmalloc(sizeof(pid_list));
114    last->next = curr;
115    curr->pid = pid;
116    curr->next = NULL;
117    return 1;
118}
119
120static int fuser_add_inode(inode_list *ilist, dev_t dev, ino_t inode)
121{
122    inode_list *curr = NULL, *last = NULL;
123
124    if(!ilist->inode && !ilist->dev) {
125        ilist->dev = dev;
126        ilist->inode = inode;
127    }
128    curr = ilist;
129    while(curr != NULL) {
130        if(curr->inode == inode && curr->dev == dev) return 1;
131        last = curr;
132        curr = curr->next;
133    }
134    curr = xmalloc(sizeof(inode_list));
135    last->next = curr;
136    curr->dev = dev;
137    curr->inode = inode;
138    curr->next = NULL;
139    return 1;
140}
141
142static int fuser_scan_proc_net(int opts, const char *proto,
143    int port, inode_list *ilist)
144{
145    char path[sizeof(FUSER_PROC_DIR)+12], line[FUSER_MAX_LINE+1];
146    char addr[128];
147    ino_t tmp_inode;
148    dev_t tmp_dev;
149    long long  uint64_inode;
150    int tmp_port;
151    FILE *f;
152
153    if(!fuser_find_socket_dev(&tmp_dev)) tmp_dev = 0;
154    sprintf(path, "%s/net/%s", FUSER_PROC_DIR, proto);
155
156    if (!(f = fopen(path, "r"))) return 0;
157    while(fgets(line, FUSER_MAX_LINE, f)) {
158        if(sscanf(line,
159            "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x "
160            "%*x:%*x %*x %*d %*d %llu",
161            addr, &tmp_port, &uint64_inode) == 3) {
162            if((strlen(addr) == 8) &&
163                (opts & FUSER_OPT_IP6)) continue;
164            else if((strlen(addr) > 8) &&
165                (opts & FUSER_OPT_IP4)) continue;
166            if(tmp_port == port) {
167                tmp_inode = uint64_inode;
168                fuser_add_inode(ilist, tmp_dev, tmp_inode);
169            }
170        }
171
172    }
173    fclose(f);
174    return 1;
175}
176
177static int fuser_search_dev_inode(int opts, inode_list *ilist,
178    dev_t dev, ino_t inode)
179{
180    inode_list *curr;
181    curr = ilist;
182
183    while(curr) {
184        if((opts & FUSER_OPT_MOUNT) &&  curr->dev == dev)
185            return 1;
186        if(curr->inode == inode && curr->dev == dev)
187            return 1;
188        curr = curr->next;
189    }
190    return 0;
191}
192
193static int fuser_scan_pid_maps(int opts, const char *fname, pid_t pid,
194    inode_list *ilist, pid_list *plist)
195{
196    FILE *file;
197    char line[FUSER_MAX_LINE + 1];
198    int major, minor;
199    ino_t inode;
200    long long uint64_inode;
201    dev_t dev;
202
203    if (!(file = fopen(fname, "r"))) return 0;
204    while (fgets(line, FUSER_MAX_LINE, file)) {
205        if(sscanf(line, "%*s %*s %*s %x:%x %llu",
206            &major, &minor, &uint64_inode) != 3) continue;
207        inode = uint64_inode;
208        if(major == 0 && minor == 0 && inode == 0) continue;
209        dev = makedev(major, minor);
210        if(fuser_search_dev_inode(opts, ilist, dev, inode)) {
211            fuser_add_pid(plist, pid);
212        }
213
214    }
215    fclose(file);
216    return 1;
217}
218
219static int fuser_scan_link(int opts, const char *lname, pid_t pid,
220    inode_list *ilist, pid_list *plist)
221{
222    ino_t inode;
223    dev_t dev;
224
225    if(!fuser_file_to_dev_inode(lname, &dev, &inode)) return 0;
226    if(fuser_search_dev_inode(opts, ilist, dev, inode))
227        fuser_add_pid(plist, pid);
228    return 1;
229}
230
231static int fuser_scan_dir_links(int opts, const char *dname, pid_t pid,
232    inode_list *ilist, pid_list *plist)
233{
234    DIR *d;
235    struct dirent *de;
236    char *lname;
237
238    if((d = opendir(dname))) {
239        while((de = readdir(d)) != NULL) {
240            lname = concat_subpath_file(dname, de->d_name);
241            if(lname == NULL)
242                continue;
243            fuser_scan_link(opts, lname, pid, ilist, plist);
244            free(lname);
245        }
246        closedir(d);
247    }
248    else return 0;
249    return 1;
250
251}
252
253static int fuser_scan_proc_pids(int opts, inode_list *ilist, pid_list *plist)
254{
255    DIR *d;
256    struct dirent *de;
257    pid_t pid;
258    char *dname;
259
260    if(!(d = opendir(FUSER_PROC_DIR))) return 0;
261    while((de = readdir(d)) != NULL) {
262        pid = (pid_t)atoi(de->d_name);
263        if(!pid) continue;
264        dname = concat_subpath_file(FUSER_PROC_DIR, de->d_name);
265        if(chdir(dname) < 0) {
266            free(dname);
267            continue;
268        }
269        free(dname);
270        fuser_scan_link(opts, "cwd", pid, ilist, plist);
271        fuser_scan_link(opts, "exe", pid, ilist, plist);
272        fuser_scan_link(opts, "root", pid, ilist, plist);
273        fuser_scan_dir_links(opts, "fd", pid, ilist, plist);
274        fuser_scan_dir_links(opts, "lib", pid, ilist, plist);
275        fuser_scan_dir_links(opts, "mmap", pid, ilist, plist);
276        fuser_scan_pid_maps(opts, "maps", pid, ilist, plist);
277        chdir("..");
278    }
279    closedir(d);
280    return 1;
281}
282
283static int fuser_print_pid_list(pid_list *plist)
284{
285    pid_list *curr = plist;
286
287    if(plist == NULL) return 0;
288    while(curr != NULL) {
289        if(curr->pid > 0) printf("%d ", curr->pid);
290        curr = curr->next;
291    }
292    printf("\n");
293    return 1;
294}
295
296static int fuser_kill_pid_list(pid_list *plist, int sig)
297{
298    pid_list *curr = plist;
299    pid_t mypid = getpid();
300    int success = 1;
301
302    if(plist == NULL) return 0;
303    while(curr != NULL) {
304        if(curr->pid > 0 && curr->pid != mypid) {
305            if (kill(curr->pid, sig) != 0) {
306                bb_perror_msg(
307                    "Could not kill pid '%d'", curr->pid);
308                success = 0;
309            }
310        }
311        curr = curr->next;
312    }
313    return success;
314}
315
316int fuser_main(int argc, char **argv)
317{
318    int port, i, optn;
319    int* fni; /* file name indexes of argv */
320    int fnic = 0;  /* file name index count */
321    const char *proto;
322    static int opt = 0; /* FUSER_OPT_ */
323    dev_t dev;
324    ino_t inode;
325    pid_list *pids;
326    inode_list *inodes;
327    int killsig = SIGTERM;
328    int success = 1;
329
330    if (argc < 2)
331        bb_show_usage();
332
333    fni = xmalloc(sizeof(int));
334    for(i=1;i<argc;i++) {
335        optn = fuser_option(argv[i]);
336        if(optn) opt |= optn;
337        else if(argv[i][0] == '-') {
338            if(!(u_signal_names(argv[i]+1, &killsig, 0)))
339                killsig = SIGTERM;
340        }
341        else {
342            fni = xrealloc(fni, sizeof(int) * (fnic+2));
343            fni[fnic++] = i;
344        }
345    }
346    if(!fnic) return 1;
347
348    pids = xmalloc(sizeof(pid_list));
349    inodes = xmalloc(sizeof(inode_list));
350    for(i=0;i<fnic;i++) {
351        if(fuser_parse_net_arg(argv[fni[i]], &proto, &port)) {
352            fuser_scan_proc_net(opt, proto, port, inodes);
353        }
354        else {
355            if(!fuser_file_to_dev_inode(
356                argv[fni[i]], &dev, &inode)) {
357                free(pids);
358                free(inodes);
359                bb_perror_msg_and_die(
360                    "Could not open '%s'", argv[fni[i]]);
361            }
362            fuser_add_inode(inodes, dev, inode);
363        }
364    }
365    success = fuser_scan_proc_pids(opt, inodes, pids);
366    /* if the first pid in the list is 0, none have been found */
367    if(pids->pid == 0) success = 0;
368    if(success) {
369        if(opt & FUSER_OPT_KILL) {
370            success = fuser_kill_pid_list(pids, killsig);
371        }
372        else if(!(opt & FUSER_OPT_SILENT)) {
373            success = fuser_print_pid_list(pids);
374        }
375    }
376    free(pids);
377    free(inodes);
378    /* return 0 on (success == 1) 1 otherwise */
379    return (success != 1);
380}
Note: See TracBrowser for help on using the repository browser.