Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/procps/fuser.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 8180 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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