source: branches/3.2/mindi-busybox/procps/fuser.c @ 3232

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