Magellan Linux

Diff of /tags/mkinitrd-6_5_1/busybox/procps/fuser.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 984 by niro, Sun May 30 11:32:42 2010 UTC revision 1123 by niro, Wed Aug 18 21:56:57 2010 UTC
# Line 31  typedef struct pid_list { Line 31  typedef struct pid_list {
31   pid_t pid;   pid_t pid;
32  } pid_list;  } pid_list;
33    
 static dev_t find_socket_dev(void)  
 {  
  int fd = socket(AF_INET, SOCK_DGRAM, 0);  
  if (fd >= 0) {  
  struct stat buf;  
  int r = fstat(fd, &buf);  
  close(fd);  
  if (r == 0)  
  return buf.st_dev;  
  }  
  return 0;  
 }  
34    
35  static int file_to_dev_inode(const char *filename, dev_t *dev, ino_t *inode)  struct globals {
36  {   pid_list *pid_list_head;
37   struct stat f_stat;   inode_list *inode_list_head;
38   if (stat(filename, &f_stat))  };
39   return 0;  #define G (*(struct globals*)&bb_common_bufsiz1)
40   *inode = f_stat.st_ino;  #define INIT_G() do { } while (0)
41   *dev = f_stat.st_dev;  
  return 1;  
 }  
42    
43  static char *parse_net_arg(const char *arg, unsigned *port)  static void add_pid(const pid_t pid)
44  {  {
45   char path[20], tproto[5];   pid_list **curr = &G.pid_list_head;
46    
47   if (sscanf(arg, "%u/%4s", port, tproto) != 2)   while (*curr) {
48   return NULL;   if ((*curr)->pid == pid)
49   sprintf(path, "/proc/net/%s", tproto);   return;
50   if (access(path, R_OK) != 0)   curr = &(*curr)->next;
51   return NULL;   }
  return xstrdup(tproto);  
 }  
52    
53  static pid_list *add_pid(pid_list *plist, pid_t pid)   *curr = xzalloc(sizeof(pid_list));
54  {   (*curr)->pid = pid;
  pid_list *curr = plist;  
  while (curr != NULL) {  
  if (curr->pid == pid)  
  return plist;  
  curr = curr->next;  
  }  
  curr = xmalloc(sizeof(pid_list));  
  curr->pid = pid;  
  curr->next = plist;  
  return curr;  
55  }  }
56    
57  static inode_list *add_inode(inode_list *ilist, dev_t dev, ino_t inode)  static void add_inode(const struct stat *st)
58  {  {
59   inode_list *curr = ilist;   inode_list **curr = &G.inode_list_head;
60   while (curr != NULL) {  
61   if (curr->inode == inode && curr->dev == dev)   while (*curr) {
62   return ilist;   if ((*curr)->dev == st->st_dev
63   curr = curr->next;   && (*curr)->inode == st->st_ino
64   }   ) {
65   curr = xmalloc(sizeof(inode_list));   return;
66   curr->dev = dev;   }
67   curr->inode = inode;   curr = &(*curr)->next;
68   curr->next = ilist;   }
69   return curr;  
70     *curr = xzalloc(sizeof(inode_list));
71     (*curr)->dev = st->st_dev;
72     (*curr)->inode = st->st_ino;
73  }  }
74    
75  static inode_list *scan_proc_net(const char *proto,  static void scan_proc_net(const char *path, unsigned port)
  unsigned port, inode_list *ilist)  
76  {  {
77   char path[20], line[MAX_LINE + 1];   char line[MAX_LINE + 1];
  ino_t tmp_inode;  
  dev_t tmp_dev;  
78   long long uint64_inode;   long long uint64_inode;
79   unsigned tmp_port;   unsigned tmp_port;
80   FILE *f;   FILE *f;
81     struct stat st;
82     int fd;
83    
84   tmp_dev = find_socket_dev();   /* find socket dev */
85     st.st_dev = 0;
86     fd = socket(AF_INET, SOCK_DGRAM, 0);
87     if (fd >= 0) {
88     fstat(fd, &st);
89     close(fd);
90     }
91    
  sprintf(path, "/proc/net/%s", proto);  
92   f = fopen_for_read(path);   f = fopen_for_read(path);
93   if (!f)   if (!f)
94   return ilist;   return;
95    
96   while (fgets(line, MAX_LINE, f)) {   while (fgets(line, MAX_LINE, f)) {
97   char addr[68];   char addr[68];
# Line 124  static inode_list *scan_proc_net(const c Line 105  static inode_list *scan_proc_net(const c
105   if (len > 8 && (option_mask32 & OPT_IP4))   if (len > 8 && (option_mask32 & OPT_IP4))
106   continue;   continue;
107   if (tmp_port == port) {   if (tmp_port == port) {
108   tmp_inode = uint64_inode;   st.st_ino = uint64_inode;
109   ilist = add_inode(ilist, tmp_dev, tmp_inode);   add_inode(&st);
110   }   }
111   }   }
112   }   }
113   fclose(f);   fclose(f);
  return ilist;  
114  }  }
115    
116  static int search_dev_inode(inode_list *ilist, dev_t dev, ino_t inode)  static int search_dev_inode(const struct stat *st)
117  {  {
118     inode_list *ilist = G.inode_list_head;
119    
120   while (ilist) {   while (ilist) {
121   if (ilist->dev == dev) {   if (ilist->dev == st->st_dev) {
122   if (option_mask32 & OPT_MOUNT)   if (option_mask32 & OPT_MOUNT)
123   return 1;   return 1;
124   if (ilist->inode == inode)   if (ilist->inode == st->st_ino)
125   return 1;   return 1;
126   }   }
127   ilist = ilist->next;   ilist = ilist->next;
# Line 147  static int search_dev_inode(inode_list * Line 129  static int search_dev_inode(inode_list *
129   return 0;   return 0;
130  }  }
131    
132  static pid_list *scan_pid_maps(const char *fname, pid_t pid,  static void scan_pid_maps(const char *fname, pid_t pid)
  inode_list *ilist, pid_list *plist)  
133  {  {
134   FILE *file;   FILE *file;
135   char line[MAX_LINE + 1];   char line[MAX_LINE + 1];
136   int major, minor;   int major, minor;
  ino_t inode;  
137   long long uint64_inode;   long long uint64_inode;
138   dev_t dev;   struct stat st;
139    
140   file = fopen_for_read(fname);   file = fopen_for_read(fname);
141   if (!file)   if (!file)
142   return plist;   return;
143    
144   while (fgets(line, MAX_LINE, file)) {   while (fgets(line, MAX_LINE, file)) {
145   if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3)   if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3)
146   continue;   continue;
147   inode = uint64_inode;   st.st_ino = uint64_inode;
148   if (major == 0 && minor == 0 && inode == 0)   if (major == 0 && minor == 0 && st.st_ino == 0)
149   continue;   continue;
150   dev = makedev(major, minor);   st.st_dev = makedev(major, minor);
151   if (search_dev_inode(ilist, dev, inode))   if (search_dev_inode(&st))
152   plist = add_pid(plist, pid);   add_pid(pid);
153   }   }
154   fclose(file);   fclose(file);
  return plist;  
155  }  }
156    
157  static pid_list *scan_link(const char *lname, pid_t pid,  static void scan_link(const char *lname, pid_t pid)
  inode_list *ilist, pid_list *plist)  
158  {  {
159   ino_t inode;   struct stat st;
  dev_t dev;  
160    
161   if (!file_to_dev_inode(lname, &dev, &inode))   if (stat(lname, &st) >= 0) {
162   return plist;   if (search_dev_inode(&st))
163   if (search_dev_inode(ilist, dev, inode))   add_pid(pid);
164   plist = add_pid(plist, pid);   }
  return plist;  
165  }  }
166    
167  static pid_list *scan_dir_links(const char *dname, pid_t pid,  static void scan_dir_links(const char *dname, pid_t pid)
  inode_list *ilist, pid_list *plist)  
168  {  {
169   DIR *d;   DIR *d;
170   struct dirent *de;   struct dirent *de;
# Line 196  static pid_list *scan_dir_links(const ch Line 172  static pid_list *scan_dir_links(const ch
172    
173   d = opendir(dname);   d = opendir(dname);
174   if (!d)   if (!d)
175   return plist;   return;
176    
177   while ((de = readdir(d)) != NULL) {   while ((de = readdir(d)) != NULL) {
178   lname = concat_subpath_file(dname, de->d_name);   lname = concat_subpath_file(dname, de->d_name);
179   if (lname == NULL)   if (lname == NULL)
180   continue;   continue;
181   plist = scan_link(lname, pid, ilist, plist);   scan_link(lname, pid);
182   free(lname);   free(lname);
183   }   }
184   closedir(d);   closedir(d);
  return plist;  
185  }  }
186    
187  /* NB: does chdir internally */  /* NB: does chdir internally */
188  static pid_list *scan_proc_pids(inode_list *ilist)  static void scan_proc_pids(void)
189  {  {
190   DIR *d;   DIR *d;
191   struct dirent *de;   struct dirent *de;
192   pid_t pid;   pid_t pid;
  pid_list *plist;  
193    
194   xchdir("/proc");   xchdir("/proc");
195   d = opendir("/proc");   d = opendir("/proc");
196   if (!d)   if (!d)
197   return NULL;   return;
198    
  plist = NULL;  
199   while ((de = readdir(d)) != NULL) {   while ((de = readdir(d)) != NULL) {
200   pid = (pid_t)bb_strtou(de->d_name, NULL, 10);   pid = (pid_t)bb_strtou(de->d_name, NULL, 10);
201   if (errno)   if (errno)
202   continue;   continue;
203   if (chdir(de->d_name) < 0)   if (chdir(de->d_name) < 0)
204   continue;   continue;
205   plist = scan_link("cwd", pid, ilist, plist);   scan_link("cwd", pid);
206   plist = scan_link("exe", pid, ilist, plist);   scan_link("exe", pid);
207   plist = scan_link("root", pid, ilist, plist);   scan_link("root", pid);
208   plist = scan_dir_links("fd", pid, ilist, plist);  
209   plist = scan_dir_links("lib", pid, ilist, plist);   scan_dir_links("fd", pid);
210   plist = scan_dir_links("mmap", pid, ilist, plist);   scan_dir_links("lib", pid);
211   plist = scan_pid_maps("maps", pid, ilist, plist);   scan_dir_links("mmap", pid);
212    
213     scan_pid_maps("maps", pid);
214   xchdir("/proc");   xchdir("/proc");
215   }   }
216   closedir(d);   closedir(d);
  return plist;  
 }  
   
 static int print_pid_list(pid_list *plist)  
 {  
  while (plist != NULL) {  
  printf("%u ", (unsigned)plist->pid);  
  plist = plist->next;  
  }  
  bb_putchar('\n');  
  return 1;  
 }  
   
 static int kill_pid_list(pid_list *plist, int sig)  
 {  
  pid_t mypid = getpid();  
  int success = 1;  
   
  while (plist != NULL) {  
  if (plist->pid != mypid) {  
  if (kill(plist->pid, sig) != 0) {  
  bb_perror_msg("kill pid %u", (unsigned)plist->pid);  
  success = 0;  
  }  
  }  
  plist = plist->next;  
  }  
  return success;  
217  }  }
218    
219  int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
220  int fuser_main(int argc UNUSED_PARAM, char **argv)  int fuser_main(int argc UNUSED_PARAM, char **argv)
221  {  {
222   pid_list *plist;   pid_list *plist;
223   inode_list *ilist;   pid_t mypid;
224   char **pp;   char **pp;
225   dev_t dev;   struct stat st;
  ino_t inode;  
226   unsigned port;   unsigned port;
227   int opt;   int opt;
228   int success;   int exitcode;
229   int killsig;   int killsig;
230  /*  /*
231  fuser [options] FILEs or PORT/PROTOs  fuser [OPTIONS] FILE or PORT/PROTO
232  Find processes which use FILEs or PORTs  Find processes which use FILEs or PORTs
233          -m      Find processes which use same fs as FILEs          -m      Find processes which use same fs as FILEs
234          -4      Search only IPv4 space          -4      Search only IPv4 space
235          -6      Search only IPv6 space          -6      Search only IPv6 space
236          -s      Silent: just exit with 0 if any processes are found          -s      Don't display PIDs
237          -k      Kill found processes (otherwise display PIDs)          -k      Kill found processes
238          -SIGNAL Signal to send (default: TERM)          -SIGNAL Signal to send (default: KILL)
239  */  */
240   /* Handle -SIGNAL. Oh my... */   /* Handle -SIGNAL. Oh my... */
241   killsig = SIGTERM;   killsig = SIGKILL; /* yes, the default is not SIGTERM */
242   pp = argv;   pp = argv;
243   while (*++pp) {   while (*++pp) {
244   char *arg = *pp;   char *arg = *pp;
# Line 313  Find processes which use FILEs or PORTs Line 260  Find processes which use FILEs or PORTs
260   break;   break;
261   }   }
262    
263     opt_complementary = "-1"; /* at least one param */
264   opt = getopt32(argv, OPTION_STRING);   opt = getopt32(argv, OPTION_STRING);
265   argv += optind;   argv += optind;
266    
  ilist = NULL;  
267   pp = argv;   pp = argv;
268   while (*pp) {   while (*pp) {
269   char *proto = parse_net_arg(*pp, &port);   /* parse net arg */
270   if (proto) { /* PORT/PROTO */   char path[20], tproto[5];
271   ilist = scan_proc_net(proto, port, ilist);   if (sscanf(*pp, "%u/%4s", &port, tproto) != 2)
272   free(proto);   goto file;
273     sprintf(path, "/proc/net/%s", tproto);
274     if (access(path, R_OK) != 0) { /* PORT/PROTO */
275     scan_proc_net(path, port);
276   } else { /* FILE */   } else { /* FILE */
277   if (!file_to_dev_inode(*pp, &dev, &inode))   file:
278   bb_perror_msg_and_die("can't open '%s'", *pp);   xstat(*pp, &st);
279   ilist = add_inode(ilist, dev, inode);   add_inode(&st);
280   }   }
281   pp++;   pp++;
282   }   }
283    
284   plist = scan_proc_pids(ilist); /* changes dir to "/proc" */   scan_proc_pids(); /* changes dir to "/proc" */
285    
286   if (!plist)   mypid = getpid();
287   return EXIT_FAILURE;   plist = G.pid_list_head;
288   success = 1;   while (1) {
289   if (opt & OPT_KILL) {   if (!plist)
290   success = kill_pid_list(plist, killsig);   return EXIT_FAILURE;
291   } else if (!(opt & OPT_SILENT)) {   if (plist->pid != mypid)
292   success = print_pid_list(plist);   break;
293     plist = plist->next;
294   }   }
295   return (success != 1); /* 0 == success */  
296     exitcode = EXIT_SUCCESS;
297     do {
298     if (plist->pid != mypid) {
299     if (opt & OPT_KILL) {
300     if (kill(plist->pid, killsig) != 0) {
301     bb_perror_msg("kill pid %u", (unsigned)plist->pid);
302     exitcode = EXIT_FAILURE;
303     }
304     }
305     if (!(opt & OPT_SILENT)) {
306     printf("%u ", (unsigned)plist->pid);
307     }
308     }
309     plist = plist->next;
310     } while (plist);
311    
312     if (!(opt & (OPT_SILENT))) {
313     bb_putchar('\n');
314     }
315    
316     return exitcode;
317  }  }

Legend:
Removed from v.984  
changed lines
  Added in v.1123