~vcs-imports/busybox/trunk

« back to all changes in this revision

Viewing changes to procps/fuser.c

  • Committer: Eric Andersen
  • Date: 1999-11-24 09:04:33 UTC
  • Revision ID: git-v1:b99df0fd65abe3245fa2d04115326100847f865e
First draft

Show diffs side-by-side

added added

removed removed

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