]> granicus.if.org Git - psmisc/commitdiff
moved fusernew as fuser and fuser as oldfuser
authorCraig Small <csmall@users.sourceforge.net>
Fri, 8 Jul 2005 02:25:04 +0000 (02:25 +0000)
committerCraig Small <csmall@users.sourceforge.net>
Fri, 8 Jul 2005 02:25:04 +0000 (02:25 +0000)
src/.cvsignore
src/Makefile.am
src/fuser.c
src/fusernew.c [deleted file]
src/oldfuser.c [new file with mode: 0644]

index aad160d6fa90357e99a7736f585a830171dfdea3..02374ac6b88952a8afffb56cdd91682ba0046b16 100644 (file)
@@ -1,5 +1,5 @@
 fuser
-fusernew
+oldfuser
 killall
 pstree
 pstree.x11
index 516ae733262186db1eaa9350af697927a3890627..52225908a2e504bef0fe4cf27c5b741b630658d8 100644 (file)
@@ -1,11 +1,11 @@
 
 AM_CFLAGS = -Wall -DLOCALEDIR=\"/usr/share/locale\"
 
-bin_PROGRAMS = fuser killall pstree fusernew
+bin_PROGRAMS = fuser killall pstree oldfuser
 
-fuser_SOURCES = fuser.c comm.h signals.c signals.h loop.h i18n.h
+oldfuser_SOURCES = oldfuser.c comm.h signals.c signals.h loop.h i18n.h
 
-fusernew_SOURCES = fusernew.c comm.h signals.c signals.h i18n.h fuser.h
+fuser_SOURCES = fuser.c comm.h signals.c signals.h i18n.h fuser.h
 
 killall_SOURCES = killall.c comm.h signals.c signals.h i18n.h
 
index acf07d926dc9813dc56bf704e33f5f9b80fad11d..131a9447644f7d22a53c37566a8624b7a55354ab 100644 (file)
@@ -1,8 +1,10 @@
 /*
  * fuser.c - identify processes using files
  *
- * Copyright (C) 1993-2002 Werner Almesberger
- * Copyright (C) 2002-2005 Craig Small
+ * Based on fuser.c Copyright (C) 1993-2005 Werner Almesberger and Craig Small
+ *
+ * Completely re-written
+ * Copyright (C) 2005 Craig Small
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <config.h>
 #endif
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <signal.h>
-#include <limits.h>
-#include <netdb.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
+#include <errno.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
-#include <netinet/in.h>
+#include <sys/socket.h>
 #include <arpa/inet.h>
-#ifdef __linux__
-#include <linux/kdev_t.h>      /* for MKDEV */
-#include <linux/major.h>       /* for LOOP_MAJOR */
-#endif
-#include <errno.h>
+#include <netinet/in.h>
+#include <pwd.h>
+#include <netdb.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <mntent.h>
 
+#include "fuser.h"
 #include "i18n.h"
-#include "comm.h"
-#include "loop.h"         /* for loop_info */
-#include "signals.h"
-
 
-#define PROC_BASE  "/proc"
-#define UID_UNKNOWN -1
 #define NAME_FIELD 20          /* space reserved for file name */
+/* Function defines */
+static void add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid, const char access);
+static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access);
+static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access);
+static struct stat *get_pidstat(const pid_t pid, const char *filename);
+static uid_t getpiduid(const pid_t pid);
+static void print_matches(struct names *names_head, const opt_type opts);
+static void kill_matched_proc(struct procs *pptr, const opt_type opts);
+
+static dev_t get_netdev(void);
+int parse_mount(struct names *this_name, struct device_list **dev_list);
+static void add_device(struct device_list **dev_list, struct names  *this_name, dev_t device);
+void scan_mount_devices(const opt_type opts, struct mountdev_list **mount_devices);
+static void debug_match_lists(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head);
+
+static void usage (const char *errormsg)
+{
+       if (errormsg != NULL)
+               fprintf(stderr, "%s\n", errormsg);
 
-#define MAX_LINE 256           /* longest line we may ever find in /proc */
-
+  fprintf (stderr, _(
+    "usage: fuser [ -a | -s | -c ] [ -n space ] [ -signal ] [ -kimuv ] name ...\n"
+    "             [ - ] [ -n space ] [ -signal ] [ -kimuv ] name ...\n"
+    "       fuser -l\n"
+    "       fuser -V\n\n"
+    "    -a        display unused files too\n"
+    "    -c        mounted FS\n"
+    "    -f        silently ignored (for POSIX compatibility)\n"
+    "    -k        kill processes accessing that file\n"
+    "    -i        ask before killing (ignored without -k)\n"
+    "    -l        list signal names\n"
+    "    -m        mounted FS\n"
+    "    -n space  search in the specified name space (file, udp, or tcp)\n"
+    "    -s        silent operation\n"
+    "    -signal   send signal instead of SIGKILL\n"
+    "    -u        display user ids\n"
+    "    -v        verbose output\n"
+    "    -V        display version information\n"
+    "    -4        search IPv4 sockets only\n"
+    "    -6        search IPv6 sockets only\n"
+    "    -         reset options\n\n"
+    "  udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
+  exit (1);
+}
 
-#ifndef LOOP_MAJOR             /* don't count on the headers too much ... */
-#define LOOP_MAJOR 7
-#endif
+void print_version()
+{
+  fprintf(stderr, _("fuser (psmisc) %s\n"), VERSION);
+  fprintf(stderr, _(
+    "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
+  fprintf(stderr, _(
+    "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
+    "This is free software, and you are welcome to redistribute it under\n"
+    "the terms of the GNU General Public License.\n"
+    "For more information about these matters, see the files named COPYING.\n"));
+}
 
-#ifndef MAJOR
-#define MAJOR(arg) 6           /* something that doesn't = LOOP_MAJOR */
-#endif
+static void scan_procs(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head)
+{
+       DIR *topproc_dir;
+       struct dirent *topproc_dent;
+       char *fd_dirpath, *fd_pathname;
+       struct inode_list *ino_tmp;
+       struct device_list *dev_tmp;
+       pid_t pid, my_pid;
+       uid_t uid;
+       struct stat *cwd_stat, *exe_stat, *root_stat;
+
+       if ( (fd_dirpath = malloc(MAX_PATHNAME)) == NULL)
+               return;
+       if ( (fd_pathname = malloc(MAX_PATHNAME)) == NULL)
+               return;
+
+       if ( (topproc_dir = opendir("/proc")) == NULL) {
+               fprintf(stderr, "Cannot open /proc directory: %s\n", strerror(errno));
+               exit(1);
+       }
+       my_pid = getpid();
+       while ( (topproc_dent = readdir(topproc_dir)) != NULL) {
+               if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */
+                       continue;
+               pid = atoi(topproc_dent->d_name);
+               /* Dont print myself */
+               if (pid == my_pid)
+                       continue;
+               uid = getpiduid(pid);
+
+               root_stat = get_pidstat(pid, "root");
+               cwd_stat = get_pidstat(pid, "cwd");
+               exe_stat = get_pidstat(pid, "exe");
+               /* Scan the devices */
+               for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
+                       if (exe_stat != NULL && exe_stat->st_dev == dev_tmp->device) 
+                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_EXE);
+                       if (root_stat != NULL && root_stat->st_dev == dev_tmp->device) 
+                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_ROOT);
+                       if (cwd_stat != NULL && cwd_stat->st_dev == dev_tmp->device) 
+                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_CWD);
+               }
+               for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
+                       if (exe_stat != NULL) {
+                               if (exe_stat->st_dev == ino_tmp->device && exe_stat->st_ino == ino_tmp->inode) {
+                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_EXE);
+                               }
+                       }
+                       if (root_stat != NULL) {
+                               if (root_stat->st_dev == ino_tmp->device && root_stat->st_ino == ino_tmp->inode){
+                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_ROOT);
+                               }
+
+                       }
+                       if (cwd_stat != NULL){
+                               if (cwd_stat->st_dev == ino_tmp->device && cwd_stat->st_ino == ino_tmp->inode) {
+                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
+                               }
+                       }
+               }
+               check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP);
+               check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP);
+               check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE);
+               check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
 
-#ifndef MKDEV
-#define MKDEV(arg1, arg2) mknod("/dev/Isuck", arg1, arg2) /* this is wrong */
-#endif
+       } /* while topproc_dent */
+       closedir(topproc_dir);
+}
+static void add_inode(struct inode_list **ino_list, struct names  *this_name, dev_t device, ino_t inode)
+{
+       struct inode_list *ino_tmp, *ino_head;
 
+       ino_head = *ino_list;
 
-#define REF_FILE   1           /* an open file */
-#define REF_ROOT   2           /* current root */
-#define REF_CWD    4           /* current directory */
-#define REF_EXE    8           /* executable */
-#define REF_MMAP  16           /* mmap'ed file or library */
+       if ( (ino_tmp = malloc(sizeof(struct inode_list))) == NULL)
+               return;
+       ino_tmp->name = this_name;
+       ino_tmp->device = device;
+       ino_tmp->inode = inode;
+       ino_tmp->next = ino_head;
+       *ino_list = ino_tmp;
+}
 
-#define FLAG_KILL  1           /* kill process */
-#define FLAG_UID   2           /* show uid */
-#define FLAG_VERB  4           /* show verbose output */
-#define FLAG_DEV   8           /* show all processes using this device */
-#define FLAG_ASK  16           /* ask before killing a process */
+static void add_device(struct device_list **dev_list, struct names  *this_name, dev_t device)
+{
+       struct device_list *dev_tmp, *dev_head;
 
+       /*printf("Adding device %s %d\n", this_name->filename, device);*/
+       dev_head = *dev_list;
 
-typedef struct _net_cache
-{
-  struct sockaddr_storage rmt_addr;
-  int lcl_port;
-  int rmt_port;
-  ino_t ino;
-  struct _net_cache *next;
+       if ( (dev_tmp = malloc(sizeof(struct device_list))) == NULL)
+               return;
+       dev_tmp->name = this_name;
+       dev_tmp->device = device;
+       dev_tmp->next = dev_head;
+       *dev_list = dev_tmp;
 }
-NET_CACHE;
 
-typedef struct _unix_cache
+static void add_ip_conn(struct ip_connections **ip_list, const char *protocol, struct names *this_name, const int lcl_port, const int rmt_port, unsigned long rmt_address)
 {
-  dev_t fs_dev;
-  ino_t fs_ino;
-  ino_t net_ino;
-  struct _unix_cache *next;
-}
-UNIX_CACHE;
+       struct ip_connections *ip_tmp, *ip_head;
 
-typedef struct
-{
-  const char *name;
-  NET_CACHE *cache;
-  int once;
-}
-SPACE_DSC;
+       ip_head = *ip_list;
 
-typedef enum
-{ it_proc, it_mount, it_loop, it_swap }
-ITEM_TYPE;
+       if ( (ip_tmp = malloc(sizeof(struct ip_connections))) == NULL)
+               return;
+       ip_tmp->name = this_name;
+       ip_tmp->lcl_port = lcl_port;
+       ip_tmp->rmt_port = rmt_port;
+       ip_tmp->rmt_address.s_addr = rmt_address;
+       ip_tmp->next = ip_head;
 
-typedef struct item_dsc
-{
-  ITEM_TYPE type;
-  union
-  {
-    struct
-    {
-      pid_t pid;
-      int uid;                 /* must also accept UID_UNKNOWN */
-      int ref_set;
-    }
-    proc;
-    struct
-    {
-      const char *path;
-    }
-    misc;
-  }
-  u;
-  struct item_dsc *next;
+       *ip_list = ip_tmp;
 }
-ITEM_DSC;
 
-typedef struct file_dsc
+static void add_ip6_conn(struct ip6_connections **ip_list, const char *protocol, struct names *this_name, const int lcl_port, const int rmt_port, struct in6_addr rmt_address)
 {
-  const char *name;            /* NULL if previous entry has name */
-  dev_t dev;
-  ino_t ino;
-  int flags, sig_num;
-  SPACE_DSC *name_space;       /* or NULL if no indication */
-  ITEM_DSC *items;
-  struct file_dsc *named, *next;
-}
-FILE_DSC;
-
-static SPACE_DSC name_spaces[] = {
-  {"file", NULL, 0},           /* must be first */
-  {"tcp", NULL, 0},
-  {"udp", NULL, 0},
-  {NULL, NULL, 0}
-};
+       struct ip6_connections *ip_tmp, *ip_head;
 
+       ip_head = *ip_list;
 
-static FILE_DSC *files = NULL;
-static FILE_DSC *last_named = NULL;
-static UNIX_CACHE *unix_cache = NULL;
-static pid_t self;
-static int all = 0, found_item = 0;
-static dev_t net_dev;
-static int ipv4only = 0, ipv6only = 0;
+       if ( (ip_tmp = malloc(sizeof(struct ip6_connections))) == NULL)
+               return;
+       ip_tmp->name = this_name;
+       ip_tmp->lcl_port = lcl_port;
+       ip_tmp->rmt_port = rmt_port;
+       memcpy(&(ip_tmp->rmt_port),&(rmt_port),sizeof(struct in6_addr));
+       ip_tmp->next = ip_head;
 
+       *ip_list = ip_tmp;
+}
 
-static void
-parse_net_file (SPACE_DSC * dsc,char *filename, NET_CACHE **lastptr,int version )
+static void add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid, const char access)
 {
-  FILE *file;
-  NET_CACHE *new, *last;
-  char line[MAX_LINE + 1];
-  char rmt_addr[128];
-  char addr6[128];
-  unsigned long tmp_ino;
-
-  if (!(file = fopen (filename, "r")))
-    {
-      perror (filename);
-      exit (1);
-    }
-  last = *lastptr;
-  (void) fgets (line, MAX_LINE, file);
-  while (fgets (line, MAX_LINE, file))
-    {
-      new = malloc (sizeof (NET_CACHE));
-      if (!new)
+       struct procs *pptr, *last_proc;
+       char *pathname;
+       char cmdname[101], *cptr;
+       int cmdlen;
+       FILE *fp;
+
+       last_proc = NULL;
+       for (pptr = name_list->matched_procs; pptr != NULL ; pptr = pptr->next)
        {
-         perror ("malloc");
-         exit (1);
+               last_proc = pptr;
+               if (pptr->pid == pid) {
+                       pptr->access |= access;
+                       return;
+               }
        }
-    if (sscanf (line, 
-        "%*d: %*x:%x %64[0-9A-Fa-f]:%x %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
-        &new->lcl_port, rmt_addr, &new->rmt_port, &tmp_ino) != 4)
-       {
-         free (new);
-         continue;
+       /* Not found */
+       if ( (pptr = malloc(sizeof (struct procs))) == NULL) {
+               fprintf(stderr,_("Cannot allocate memory for matched proc: %s\n"), strerror(errno));
+               return;
        }
-      new->ino = tmp_ino;
-      if (strlen(rmt_addr) > 8) {
-        sscanf(rmt_addr, "%08X%08X%08X%08X",
-            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[0],
-            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[1],
-            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[2],
-            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[3]);
-        inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr, addr6, sizeof(addr6));
-      } else {
-        sscanf(rmt_addr, "%X",
-            &((struct sockaddr_in *) &new->rmt_addr)->sin_addr.s_addr);
-            ((struct sockaddr *) &new->rmt_addr)->sa_family = AF_INET;
-      }
-      if (!new->ino)
-       {
-         free (new);
-         continue;
-       }
-      new->next = NULL;
-      if (last)
-       last->next = new;
-      else
-       dsc->cache = new;
-      last = new;
-    }
-  (void) fclose (file);
-  *lastptr = last;
-
-}
-
-static void
-fill_net_cache (SPACE_DSC * dsc)
-{
-  NET_CACHE *last;
-  struct stat statbuf;
-  char *buffer = malloc (strlen (PROC_BASE) + strlen (dsc->name) + 8);
-  if (!buffer)
-    return;
-
-  if (dsc->once)
-    return;
-  dsc->once = 1;
-  last = NULL;
-
-  /* Check to see if we have both namespace files, if we don't then silently
-   * not use them if not flags are specified and complain if the flags
-   * were specified.
-   */
-  
-  if (!ipv6only) {
-    sprintf (buffer, PROC_BASE "/net/%s", dsc->name);
-    if (stat(buffer, &statbuf) != 0) {
-      if (ipv4only) 
-        fprintf(stderr, _("-4 flag used but proc file %s is not readable\n"), buffer);
-    } else {
-      parse_net_file (dsc, buffer, &last,4 );
-    }
-  }
-  if (!ipv4only) {
-    sprintf (buffer, PROC_BASE "/net/%s6", dsc->name);
-    if (stat(buffer, &statbuf) != 0) {
-      if (ipv6only) 
-        fprintf(stderr, _("-6 flag used but proc file %s is not readable\n"), buffer);
-    } else {
-      parse_net_file (dsc, buffer, &last,6 );
-    }
-  }
+       pptr->pid = pid;
+       pptr->uid = uid;
+       pptr->access = access;
+       pptr->next = NULL;
+       /* set command name */
+       pptr->command = NULL;
+       if ( (asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
+                       ( (fp = fopen(pathname, "r")) != NULL) &&
+                       ( fscanf(fp, "%*d (%100[^)]", cmdname) == 1)) 
+               if ( (pptr->command = malloc(MAX_CMDNAME+1)) != NULL) {
+                       cmdlen = 0;
+                       for (cptr = cmdname; cmdlen < MAX_CMDNAME && *cptr ; cptr++) {
+                               if (isprint(*cptr))
+                                       pptr->command[cmdlen++] = *cptr;
+                               else if(cmdlen < (MAX_CMDNAME-4))
+                                       cmdlen += sprintf(&(pptr->command[cmdlen]), "\\%03o", *cptr);
+                       }
+                       pptr->command[cmdlen] = '\0';
+               }
+       if (last_proc == NULL)
+               name_list->matched_procs = pptr;
+       else
+               last_proc->next = pptr;
 }
 
-
-static void
-fill_unix_cache (void)
+int parse_mount(struct names *this_name, struct device_list **dev_list)
 {
-  static int once;
-  FILE *file;
-  UNIX_CACHE *new, *last;
-  struct stat st;
-  char *path = NULL, line[MAX_LINE + 1];
-  int ino;
-
-  if (once)
-    return;
-  once = 1;
-  if (!(file = fopen (PROC_BASE "/net/unix", "r")))
-    {
-      perror (PROC_BASE "/net/unix");
-      exit (1);
-    }
-  last = NULL;
-  (void) fgets (line, MAX_LINE, file);
-  while (fgets (line, MAX_LINE, file))
-    {
-      if (sscanf (line, "%*x: %*x %*x %*x %*x %*x %d %as", &ino, &path) != 2)
-       continue;
-      if (stat (path, &st) < 0) {
-       free (path);
-       continue;
-      }
-      free (path);
-
-      new = malloc (sizeof (UNIX_CACHE));
-      new->fs_dev = st.st_dev;
-      new->fs_ino = st.st_ino;
-      new->net_ino = ino;
-      new->next = NULL;
-      if (last)
-       last->next = new;
-      else
-       unix_cache = new;
-      last = new;
-    }
-  (void) fclose (file);
+       struct stat st;
 
+       if (stat(this_name->filename, &st) != 0) {
+               fprintf(stderr, "Cannot stat mount point %s: %s\n", 
+                               this_name->filename,
+                               strerror(errno));
+               exit(1);
+       }
+       /*printf("Debug: parse_mount() adding %s\n", this_name->filename);*/
+       add_device(dev_list, this_name, st.st_dev);
+       return 0;
 }
 
-
-static unsigned long
-try_to_find_unix_dev (ino_t inode)
+int parse_file(struct names *this_name, struct inode_list **ino_list)
 {
-  UNIX_CACHE *walk;
+       struct stat st;
 
-  for (walk = unix_cache; walk; walk = walk->next)
-    if (walk->net_ino == inode)
-      return walk->fs_dev;
-  return 0;
+       if (stat(this_name->filename, &st) != 0) {
+               fprintf(stderr,"Cannot stat %s: %s\n", this_name->filename,
+                               strerror(errno));
+               return -1;
+       }
+       /*printf("adding file %s %lX %lX\n", this_name->filename,
+                       (unsigned long)st.st_dev, (unsigned long)st.st_ino);*/
+       add_inode(ino_list, this_name, st.st_dev, st.st_ino);
+       return 0;
 }
 
-
-static void
-add_file (const char *path, dev_t device, ino_t inode,
-         pid_t pid, int ref)
+int parse_mounts(struct names *this_name, struct mountdev_list *mounts, struct device_list **dev_list, const char opts) 
 {
-  struct stat st;
-  FILE_DSC *file, *next;
-  ITEM_DSC **item, *this;
-  dev_t mount_dev;
-
-  if (device)
-    mount_dev = device;
-  else
-    mount_dev = try_to_find_unix_dev (inode);
-  for (file = files; file; file = next)
-    {
-      next = file->next;
-      if (file->flags & FLAG_DEV ? mount_dev && mount_dev == file->dev :
-         device == file->dev && inode == file->ino)
-       {
-         if (!file->name)
-           file = file->named;
-         for (item = &file->items; *item; item = &(*item)->next)
-           if ((*item)->type == it_proc && (*item)->u.proc.pid >= pid)
-             break;
-         if (*item && (*item)->u.proc.pid == pid)
-           this = *item;
-         else
-           {
-             if (!(this = malloc (sizeof (ITEM_DSC))))
-               {
-                 perror ("malloc");
-                 exit (1);
+       struct stat st;
+       struct mountdev_list *mountptr;
+       dev_t match_device;
+
+       if (stat(this_name->filename, &st) != 0) {
+               fprintf(stderr,"Cannot stat %s: %s\n", this_name->filename,
+                               strerror(errno));
+               return -1;
+       }
+       if (S_ISBLK(st.st_mode))
+               match_device = st.st_rdev;
+       else
+               match_device = st.st_dev;
+       for (mountptr = mounts ; mountptr != NULL ; mountptr = mountptr->next) {
+               if (mountptr->device == match_device) {
+                       /*printf("Debug: adding parse_mounts() adding %s\n", 
+                                       this_name->filename);*/
+                       add_device(dev_list, this_name, match_device);
                }
-             this->type = it_proc;
-             this->u.proc.pid = pid;
-             this->u.proc.uid = UID_UNKNOWN;
-             this->u.proc.ref_set = 0;
-             this->next = *item;
-             *item = this;
-             found_item = 1;
-           }
-         this->u.proc.ref_set |= ref;
-         if ((file->flags & (FLAG_UID | FLAG_VERB)) && this->u.proc.uid ==
-             UID_UNKNOWN && lstat (path, &st) >= 0)
-           this->u.proc.uid = st.st_uid;
        }
-    }
+       return 0;
 }
 
-
-static void
-add_other (ITEM_TYPE type, dev_t mount_dev,
-          dev_t device, ino_t inode, const char *path)
+int parse_inet(struct names *this_name, const int ipv6_only, const int ipv4_only, struct ip_connections **ip_list, struct ip6_connections **ip6_list)
 {
-  FILE_DSC *file, *next;
-  ITEM_DSC **item, *this;
-
-  for (file = files; file; file = next)
-    {
-      next = file->next;
-      if (file->flags & FLAG_DEV ? mount_dev == file->dev :
-         device == file->dev && inode == file->ino)
-       {
-         if (!file->name)
-           file = file->named;
-         for (item = &file->items; *item; item = &(*item)->next);
-         /* there's no easy way to suppress duplicates, so we don't */
-         if (!(this = malloc (sizeof (ITEM_DSC))))
-           {
-             perror ("malloc");
-             exit (1);
-           }
-         this->type = type;
-         if (!(this->u.misc.path = strdup (path)))
-           {
-             perror ("strdup");
-             exit (1);
-           }
-         this->next = *item;
-         *item = this;
-         found_item = 1;
+       struct addrinfo *res, *resptr;
+       struct addrinfo hints;
+       int errcode;
+       char *lcl_port_str, *rmt_addr_str, *rmt_port_str, *tmpstr, *tmpstr2;
+       in_port_t lcl_port;
+       struct sockaddr_in *sin;
+       struct sockaddr_in6 *sin6;
+       char hostspec[100];
+       char *protocol;
+       int i;
+       
+       if ( (protocol = strchr(this_name->filename, '/')) == NULL)
+               return -1;
+       protocol++;
+       if (protocol[0] == '\0')
+               return -1;
+       for (i=0; i < 99 && this_name->filename[i] != '\0' && this_name->filename[i] != '/'; i++)
+               hostspec[i] = this_name->filename[i];
+       hostspec[i] = '\0';
+
+       lcl_port_str = rmt_addr_str = rmt_port_str = NULL;
+       /* Split out the names */
+       if ( (tmpstr = strchr(hostspec, ',')) == NULL) {
+               /* Single option */
+               lcl_port_str = strdup(hostspec);
+       } else {
+               if (tmpstr == hostspec)
+                       lcl_port_str = NULL;
+               else {
+                       lcl_port_str = strdup(hostspec);
+                       *tmpstr = '\0';
+               }
+               tmpstr++;
+               if (*tmpstr != '\0') {
+                       if ( (tmpstr2 = strchr(tmpstr, ',')) == NULL) {
+                               /* Only 2 options */
+                               rmt_addr_str = tmpstr;
+                       } else {
+                               if (tmpstr2 == tmpstr)
+                                       rmt_addr_str = NULL;
+                               else {
+                                       rmt_addr_str = tmpstr;
+                                       *tmpstr2 = '\0';
+                               }
+                               tmpstr2++;
+                               if (*tmpstr2 != '\0')
+                                       rmt_port_str = tmpstr2;
+                       }
+               }
+       }
+       /*printf("parsed to lp %s rh %s rp %s\n", lcl_port_str, rmt_addr_str, rmt_port_str);*/
+
+       memset(&hints, 0, sizeof(hints));
+       if (ipv6_only) {
+               hints.ai_family = PF_INET6;
+       } else if (ipv4_only) {
+                       hints.ai_family = PF_INET;
+               } else 
+                       hints.ai_family = PF_UNSPEC;
+       if (strcmp(protocol, "tcp") == 0)
+               hints.ai_socktype = SOCK_STREAM;
+       else
+               hints.ai_socktype = SOCK_DGRAM;
+
+       if (lcl_port_str == NULL) {
+               lcl_port = 0;
+       } else {
+               /* Resolve local port first */
+               if ( (errcode = getaddrinfo(NULL, lcl_port_str, &hints, &res)) != 0) {
+                       fprintf(stderr, "Cannot resolve local port %s: %s\n",
+                                       lcl_port_str, gai_strerror(errcode));
+                       return -1;
+               }
+               if (res == NULL)
+                       return -1;
+               switch(res->ai_family) {
+                       case AF_INET:
+                               lcl_port = ((struct sockaddr_in*)(res->ai_addr))->sin_port;
+                               break;
+                       case AF_INET6:
+                               lcl_port = ((struct sockaddr_in6*)(res->ai_addr))->sin6_port;
+                               break;
+                       default:
+                               fprintf(stderr, "Uknown local port AF %d\n", res->ai_family);
+                               freeaddrinfo(res);
+                               return -1;
+               }
+               freeaddrinfo(res);
        }
-    }
+       free(lcl_port_str);
+       res = NULL;
+       if (rmt_addr_str == NULL && rmt_port_str == NULL) {
+               add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), 0, INADDR_ANY);
+               add_ip6_conn(ip6_list, protocol,this_name, ntohs(lcl_port), 0, in6addr_any);
+               return 0;
+       } else {
+               /* Resolve remote address and port */
+               if (getaddrinfo(rmt_addr_str, rmt_port_str, &hints, &res) == 0) {
+                       for(resptr = res ; resptr != NULL ; resptr = resptr->ai_next ) {
+                               switch(resptr->ai_family) {
+                                       case AF_INET:
+                                               sin = (struct sockaddr_in*)resptr->ai_addr;
+                                               add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), ntohs(sin->sin_port), sin->sin_addr.s_addr);
+                                       break;
+                               case AF_INET6:
+                                       sin6 = (struct sockaddr_in6*)resptr->ai_addr;
+                                               add_ip6_conn(ip6_list, protocol, this_name, ntohs(lcl_port), ntohs(sin6->sin6_port), sin6->sin6_addr);
+                                       break;
+                               }
+                       } /*while */
+                       return 0;
+               }
+       }
+       return 1;
 }
 
 
-static void
-check_link (const char *path, pid_t pid, int type)
-{
-  struct stat st;
-
-  if (stat (path, &st) >= 0)
-    add_file (path, st.st_dev, st.st_ino, pid, type);
-}
 
 
-static void
-check_map (const char *rel, pid_t pid, int type)
+void find_net_sockets(struct inode_list **ino_list, struct ip_connections *conn_list, const char *protocol, dev_t netdev)
 {
-  FILE *file;
-  char line[MAX_LINE + 1];
-  int major, minor;
-  ino_t inode;
-  unsigned long long tmp_inode;
-
-  if (!(file = fopen (rel, "r")))
-    return;
-  while (fgets (line, MAX_LINE, file))
-    {
-      if (sscanf (line, "%*s %*s %*s %x:%x %lld", &major, &minor, &tmp_inode) != 3)
-       continue;
-      if (major || minor || tmp_inode) {
-        inode = (ino_t)(tmp_inode);
-           add_file (rel, MKDEV (major, minor), inode, pid, type);
-      }
-    }
-  fclose (file);
-}
-
+       FILE *fp;
+       char pathname[200], line[BUFSIZ];
+       unsigned long loc_port, rmt_port;
+       unsigned long rmt_addr;
+       ino_t inode;
+       struct ip_connections *conn_tmp;
+
+       if (snprintf(pathname,200, "/proc/net/%s", protocol) < 0) 
+               return ;
+
+       if ( (fp = fopen(pathname, "r")) == NULL) {
+               fprintf(stderr, "Cannot open protocol file: %s", strerror(errno));
+               return;
+       }
+       while (fgets(line, BUFSIZ, fp) != NULL) {
+               if (sscanf(line, "%*u: %*x:%lx %08lx:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
+                       &loc_port,
+                       &rmt_addr,
+                       &rmt_port,
+                       &inode) != 4)
+                       continue;
+               /*printf("Found *:%lu with %s:%lu\n", loc_port, inet_ntoa(*((struct in_addr*)&rmt_addr)), rmt_port);*/
+               for(conn_tmp = conn_list ; conn_tmp != NULL ; conn_tmp = conn_tmp->next) {
+                       /*printf("Comparing with *.%lu %s:%lu ...", 
+                                       conn_tmp->lcl_port,
+                                       inet_ntoa(conn_tmp->rmt_address),
+                                       conn_tmp->rmt_port);*/
+                       if (conn_tmp->lcl_port == loc_port &&
+                                       conn_tmp->rmt_port == rmt_port &&
+                                       (memcmp(&(conn_tmp->rmt_address), &(rmt_addr),4) ==0)
+                          ) {
+                               /* add inode to list */
+                               add_inode(ino_list, conn_tmp->name, netdev, inode);
+                       }
+               }
+                       
 
-static void
-check_dir (const char *rel, pid_t pid, int type)
-{
-  DIR *dir;
-  struct dirent *de;
-  char *path;
-
-  if (!(dir = opendir (rel)))
-    return;
-  while ((de = readdir (dir)) != NULL)
-    if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
-      {
-       asprintf (&path, "%s/%s", rel, de->d_name);
-       check_link (path, pid, type);
-       free (path);
-      }
-  (void) closedir (dir);
+       }
+       return ;
 }
 
-
-static void
-scan_fd (void)
+void find_net6_sockets(struct inode_list **ino_list, struct ip6_connections *conn_list, const char *protocol, const dev_t netdev)
 {
-  DIR *dir;
-  struct dirent *de;
-  char *path;
-  pid_t pid;
-  int empty;
-
-  if (!(dir = opendir (PROC_BASE)))
-    {
-      perror (PROC_BASE);
-      exit (1);
-    }
-  empty = 1;
-  while ((de = readdir (dir)) != NULL)
-    if ((pid = (pid_t)atoi (de->d_name)) != 0)
-      {
-       empty = 0;
-       if (asprintf (&path, "%s/%d", PROC_BASE, pid) < 0)
-         continue;
-       if (chdir (path) >= 0)
-         {
-           check_link ("root", pid, REF_ROOT);
-           check_link ("cwd", pid, REF_CWD);
-           check_link ("exe", pid, REF_EXE);
-           check_dir ("lib", pid, REF_MMAP);
-           check_dir ("mmap", pid, REF_MMAP);
-           check_map ("maps", pid, REF_MMAP);
-           check_dir ("fd", pid, REF_FILE);
-         }
-       free (path);
-      }
-  (void) closedir (dir);
-  if (empty)
-    {
-      fprintf (stderr, _("%s is empty (not mounted ?)\n"),PROC_BASE);
-      exit (1);
-    }
+       FILE *fp;
+       char pathname[200], line[BUFSIZ];
+       unsigned long loc_port, rmt_port;
+       struct in6_addr rmt_addr;
+       unsigned int tmp_addr[4];
+       char rmt_addr6str[INET6_ADDRSTRLEN];
+       struct ip6_connections *head, *tmpptr, *tail;
+       struct ip6_connections *conn_tmp;
+       ino_t inode;
+
+       head = tmpptr = tail = NULL;
+
+       if (snprintf(pathname,200, "/proc/net/%s6", protocol) < 0) 
+               return ;
+
+       if ( (fp = fopen(pathname, "r")) == NULL) {
+               fprintf(stderr, "Cannot open protocol file: %s", strerror(errno));
+               return ;
+       }
+       while (fgets(line, BUFSIZ, fp) != NULL) {
+               if (sscanf(line, "%*u: %*x:%lx %08x%08x%08x%08x:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
+                       &loc_port, 
+                       &(tmp_addr[0]),
+                       &(tmp_addr[1]),
+                       &(tmp_addr[2]),
+                       &(tmp_addr[3]),
+                       &rmt_port, &inode) != 7)
+                       continue;
+               rmt_addr.s6_addr32[0] = tmp_addr[0];
+               rmt_addr.s6_addr32[1] = tmp_addr[1];
+               rmt_addr.s6_addr32[2] = tmp_addr[2];
+               rmt_addr.s6_addr32[3] = tmp_addr[3];
+               inet_ntop(AF_INET6, &rmt_addr, rmt_addr6str, INET6_ADDRSTRLEN);
+               /*printf("Found %ld with %s:%ld\n", loc_port, rmt_addr6str, rmt_port);*/
+               for(conn_tmp = conn_list ; conn_tmp != NULL ; conn_tmp = conn_tmp->next) {
+                       inet_ntop(AF_INET6, &conn_tmp->rmt_address, rmt_addr6str, INET6_ADDRSTRLEN);
+               /*      printf("Comparing with *.%lu %s:%lu ...", 
+                                       conn_tmp->lcl_port,
+                                       rmt_addr6str,
+                                       conn_tmp->rmt_port);*/
+                       if (conn_tmp->lcl_port == loc_port &&
+                                       conn_tmp->rmt_port == rmt_port &&
+                                       (memcmp(&(conn_tmp->rmt_address), &(rmt_addr),16) ==0)
+                          ) {
+                               add_inode(ino_list, conn_tmp->name, netdev, inode);
+                       }
+               }
+       }
 }
 
-
-static void
-scan_mounts (void)
+int main(int argc, char *argv[])
 {
-  FILE *file;
-  struct stat st_dev, st_parent, st_mounted;
-  char line[MAX_LINE + 1], *path = NULL, *mounted = NULL;
-  char *end;
-
-  if (!(file = fopen (PROC_BASE "/mounts", "r")))
-    return;                    /* old kernel */
-  while (fgets (line, MAX_LINE, file))
-    {
-      if (sscanf (line, "%as %as", &path, &mounted) != 2)
-       continue;
-      if ( stat (path, &st_dev) == 0) {
-       if (S_ISBLK (st_dev.st_mode) && MAJOR (st_dev.st_rdev) == LOOP_MAJOR) {
-               struct loop_info loopinfo;
-               int fd;
-
-               if ((fd = open(path, O_RDWR)) > 0) {
-                       if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) >= 0) {
-                               add_other(it_loop,loopinfo.lo_device,loopinfo.lo_device,loopinfo.lo_inode,path);
-                       }
-                       (void) close(fd);
-                }
+       static struct option long_options[] = {
+               {"all", 0, 0, 'a'},
+               {"mountpoint", 0, 0, 'c'},
+               {"help", 0, 0, 'h'},
+               {"interactive", 0, 0, 'i'},
+               {"kill", 0, 0, 'k'},
+               {"list", 0, 0, 'l'},
+               {"mounted", 0, 0, 'm'},
+               {"name-space", 1, 0, 'n'},
+               {"silent", 0, 0, 's'},
+               {"show-user", 0, 0, 'u'},
+               {"verbose", 0, 0, 'v'},
+               {"version", 0, 0, 'V'},
+               {0, 0, 0, 0}
+       };
+       opt_type opts;
+       int ipv4_only, ipv6_only;
+       unsigned char default_namespace = NAMESPACE_FILE;
+       struct mountdev_list *mount_devices = NULL;
+       struct device_list *match_devices = NULL;
+
+       dev_t netdev;
+       struct ip_connections *tcp_connection_list = NULL;
+       struct ip_connections *udp_connection_list = NULL;
+       struct ip6_connections *tcp6_connection_list = NULL;
+       struct ip6_connections *udp6_connection_list = NULL;
+       struct inode_list *match_inodes = NULL;
+       struct names *names_head, *this_name, *names_tail;
+       int optc, opti;
+       char *nsptr;
+
+       ipv4_only = ipv6_only = 0;
+       names_head = this_name = names_tail = NULL;
+       opts = 0;
+
+       netdev = get_netdev();
+       scan_mount_devices(opts, &mount_devices);
+
+       while ( (optc = getopt_long(argc, argv, "46acfhiklmn:suvV",
+                                       long_options, &opti)) != -1) {
+               switch(optc) {
+                       case '4':
+                               ipv4_only = 1;
+                               break;
+                       case '6':
+                               ipv6_only = 1;
+                               break;
+                       case 'a':
+                               opts |= OPT_ALLFILES;
+                               break;
+                       case 'c':
+                               opts |= OPT_MOUNTPOINT;
+                               break;
+                       case 'f':
+                               /* ignored */
+                               break;
+                       case 'h':
+                               usage(NULL);
+                               break;
+                       case 'i':
+                               opts |= OPT_INTERACTIVE;
+                               break;
+                       case 'k':
+                               opts |= OPT_KILL;
+                               break;
+                       case 'l':
+                               list_signals();
+                               return 0;
+                       case 'm':
+                               opts |= OPT_MOUNTS;
+                               break;
+                       case 'n':
+                               if (strcmp(optarg, "tcp") == 0)
+                                       default_namespace = NAMESPACE_TCP;
+                               else if (strcmp(optarg, "udp") == 0)
+                                       default_namespace = NAMESPACE_UDP;
+                               else if (strcmp(optarg, "file") == 0)
+                                       default_namespace = NAMESPACE_FILE;
+                               else 
+                                       usage(_("Invalid namespace name"));
+                               break;
+                       case 's':
+                               opts |= OPT_SILENT;
+                               break;
+                       case 'u':
+                               opts |= OPT_USER;
+                               break;
+                       case 'v':
+                               opts |= OPT_VERBOSE;
+                               break;
+                       case 'V':
+                               print_version();
+                               return 0;
+                       case '?':
+                               usage(NULL);
+                               break;
+               }
+
        }
-      }
-      if (stat (mounted, &st_mounted) < 0)
-       {
-         free (path);
-         free (mounted);
-         continue;
+       if (optind < argc) {
+               /* File specifications */
+               for( ; optind < argc ; optind++) {
+                       if ( (this_name = malloc(sizeof(struct names))) == NULL)
+                               continue;
+                       this_name->next = NULL;
+                       if (names_head == NULL)
+                               names_head = this_name;
+                       if (names_tail != NULL)
+                               names_tail->next = this_name;
+                       names_tail = this_name;
+                       /* try to find namespace spec */
+                       this_name->name_space = default_namespace;
+                       if ( ((nsptr = strchr(argv[optind], '/')) != NULL )
+                                       && ( nsptr != argv[optind] )) {
+                               if (strcmp(nsptr+1, "tcp") == 0) {
+                                       this_name->name_space = NAMESPACE_TCP;
+                                       *nsptr = '\0';
+                               } else if (strcmp(nsptr+1, "udp") == 0) {
+                                       this_name->name_space = NAMESPACE_UDP;
+                                       *nsptr = '\0';
+                               } else if (strcmp(nsptr+1, "file") == 0) {
+                                       this_name->name_space = NAMESPACE_FILE;
+                                       *nsptr = '\0';
+                               }
+                       }
+                       this_name->matched_procs = NULL;
+                       if ((opts & OPT_MOUNTPOINT) && this_name->name_space != NAMESPACE_FILE)
+                               usage(_("You can only use files with mountpoint option"));
+                       switch(this_name->name_space) {
+                               case NAMESPACE_TCP:
+                                       asprintf(&(this_name->filename), "%s/tcp", argv[optind]);
+                                       parse_inet(this_name, ipv4_only, ipv6_only, &tcp_connection_list, &tcp6_connection_list);
+                                       break;
+                               case NAMESPACE_UDP:
+                                       asprintf(&(this_name->filename), "%s/udp", argv[optind]);
+                                       parse_inet(this_name, ipv4_only, ipv6_only, &tcp_connection_list, &tcp6_connection_list);
+                                       break;
+                               default: /* FILE */
+                                       this_name->filename = strdup(argv[optind]);
+                                       parse_file(this_name, &match_inodes);
+                                       if (opts & OPT_MOUNTPOINT || opts & OPT_MOUNTS)
+                                       parse_mounts(this_name, mount_devices, &match_devices, opts);
+                                       break;
+                       }
+               } /* for */
+       } else {
+               usage(_("No process specification given"));
        }
-      if (asprintf (&end, "%s/..", mounted) < 0)
-       {
-         free (path);
-         free (mounted);
-         continue;
+       /* Check conflicting operations */
+       if (opts & OPT_MOUNTPOINT) {
+               if (opts & OPT_MOUNTS)
+                       usage(_("You cannot use the mounted and mountpoint flags together"));
        }
-
-      if (stat (end, &st_parent) >= 0)
+       if (opts & OPT_SILENT) 
        {
-         add_other (it_mount, st_parent.st_dev, st_mounted.st_dev,
-                    st_mounted.st_ino, mounted);
+               opts &= ~OPT_VERBOSE;
+               opts &= ~OPT_USER;
+               if (opts & OPT_ALLFILES)
+                       usage(_("all option cannot be used with silent option."));
        }
-      free (end);
-      free (path);
-      free (mounted);
-    }
-  (void) fclose (file);
+       if (ipv4_only && ipv6_only)
+               usage(_("You cannot search for only IPv4 and only IPv6 sockets a the same time"));
+       if (!ipv4_only) {
+               if (tcp_connection_list != NULL)
+                       find_net_sockets(&match_inodes, tcp_connection_list, "tcp",netdev);
+               if (udp_connection_list != NULL)
+                       find_net_sockets(&match_inodes, udp_connection_list, "udp",netdev);
+       }
+       if (!ipv6_only) {
+               if (tcp6_connection_list != NULL)
+                       find_net6_sockets(&match_inodes, tcp6_connection_list, "tcp",netdev);
+               if (udp6_connection_list != NULL)
+                       find_net6_sockets(&match_inodes,  udp6_connection_list, "udp",netdev);
+       }
+       /*debug_match_lists(names_head, match_inodes, match_devices);*/
+       scan_procs(names_head, match_inodes, match_devices);
+       print_matches(names_head,opts);
+       return 0;
 }
 
-
-static void
-scan_swaps (void)
+static void print_matches(struct names *names_head, const opt_type opts)
 {
-  FILE *file;
-  struct stat st;
-  char line[MAX_LINE + 1], *path, type[MAX_LINE + 1];
-
-  if (!(file = fopen (PROC_BASE "/swaps", "r")))
-    return;                    /* old kernel */
-  (void) fgets (line, MAX_LINE, file);
-  while (fgets (line, MAX_LINE, file))
-    {
-      if (sscanf (line, "%as %s", &path, type) != 2)
-       continue;               /* new kernel :-) */
-      if (strcmp (type, "file")) {
-       free (path);
-       continue;
-      }
-      if (stat (path, &st) >= 0)
-       add_other (it_swap, st.st_dev, st.st_dev, st.st_ino, path);
-      free (path);
-    }
-  (void) fclose (file);
-}
-
+       struct names *nptr;
+       struct procs *pptr;
+       char first;
+       int len;
+       struct passwd *pwent = NULL;
+       
+       if (opts & OPT_VERBOSE)
+               fprintf(stderr, _("\n%*s USER        PID ACCESS COMMAND\n"),
+                               NAME_FIELD, "");
+       for (nptr = names_head; nptr != NULL ; nptr = nptr->next) {
+               fprintf(stderr, "%s", nptr->filename);
+               first = 1;
+               len = strlen(nptr->filename);
+               if (!(opts & OPT_VERBOSE)) {
+                       putc(':', stderr);
+                       len++;
+               }
+               for (pptr = nptr->matched_procs; pptr != NULL ; pptr = pptr->next) {
+                       if (opts & (OPT_VERBOSE|OPT_USER)) {
+                               if (pwent == NULL || pwent->pw_uid != pptr->uid)
+                                       pwent = getpwuid(pptr->uid);
+                       }
+                       if (len > NAME_FIELD && (opts & OPT_VERBOSE)) {
+                               putc('\n', stderr);
+                               len=0;
+                       }
+                       if ((opts & OPT_VERBOSE) || first) 
+                               while (len++ < NAME_FIELD)
+                                       putc(' ', stderr);
+                       if (opts & OPT_VERBOSE) {
+                               if (pwent == NULL)
+                                       fprintf(stderr, " %-8s ", _("(unknown)"));
+                               else
+                                       fprintf(stderr, " %-8s ", pwent->pw_name);
+                       }
+                       printf("%6d", pptr->pid);
+                       fflush(stdout);
+                       if (opts & OPT_VERBOSE) {
+                               fprintf(stderr, " %c%c%c%c%c ",
+                                               pptr->access & ACCESS_FILE ? 'f' : '.',
+                                               pptr->access & ACCESS_ROOT ? 'r' : '.',
+                                               pptr->access & ACCESS_CWD ? 'c' : '.',
+                                               pptr->access & ACCESS_EXE ? 'e' : '.',
+                                               (pptr->access & ACCESS_MMAP) && !(pptr->access & ACCESS_EXE) ? 'm' : '.');
+                       } else {
+                               if (pptr->access & ACCESS_ROOT)
+                                       putc('r', stderr);
+                               if (pptr->access & ACCESS_CWD)
+                                       putc('c', stderr);
+                               if (pptr->access & ACCESS_EXE)
+                                       putc('e', stderr);
+                               else if (pptr->access & ACCESS_MMAP)
+                                       putc('m', stderr);
+                       }
+                       if (opts & OPT_USER) {
+                               if (pwent == NULL)
+                                       fprintf(stderr, " %-8s ", _("(unknown)"));
+                               else
+                                       fprintf(stderr, "(%s)", pwent->pw_name);
+                       }
+                       if (opts & OPT_VERBOSE) {
+                               if (pptr->command == NULL)
+                                       fprintf(stderr, "???\n");
+                               else 
+                                       fprintf(stderr, "%s\n", pptr->command);
+                       }
+                       len = 0;
+                       first = 0;
+               }
+               if (nptr->matched_procs == NULL || !(opts & OPT_VERBOSE))
+                       putc('\n', stderr);
+               if (opts & OPT_KILL)
+                       kill_matched_proc(nptr->matched_procs,  opts);
 
-static int
-ask (pid_t pid)
-{
-  int res;
-  size_t len;
-  char *line;
-
-  line = NULL;
-  len = 0;
-
-  fflush (stdout);
-  do {
-    fprintf (stderr, _("Kill process %d ? (y/N) "), pid);
-    fflush (stderr);
-
-    if (getline (&line, &len, stdin) < 0)
-      return 0;
-    /* Check for default */
-    if (line[0] == '\n') {
-      free(line);
-      return 0;
-    }
-    res = rpmatch(line);
-    if (res >= 0) {
-      free(line);
-      return res;
-    }
-  } while(1);
-  /* Never should get here */
-  return 0;
-}
+       } /* next name */
 
-static void
-kill_item (const FILE_DSC * file, const ITEM_DSC * item)
-{
-  char tmp[10];
-
-  switch (item->type)
-    {
-    case it_proc:
-      if (item->u.proc.pid == self)
-       return;
-      if ((file->flags & FLAG_ASK) && !ask (item->u.proc.pid))
-       return;
-      if (kill (item->u.proc.pid, file->sig_num) >= 0)
-       break;
-      sprintf (tmp, _("kill %d"), item->u.proc.pid);
-      perror (tmp);
-      break;
-    case it_mount:
-      fprintf (stderr, _("No automatic removal. Please use  umount %s\n"),
-              item->u.misc.path);
-      break;
-    case it_loop:
-      fprintf (stderr, _("No automatic removal. Please use  umount %s\n"),
-              item->u.misc.path);
-      break;
-    case it_swap:
-      fprintf (stderr, _("No automatic removal. Please use  swapoff %s\n"),
-              file->name);
-      break;
-    }
 }
 
-
-static void
-show_files_or_kill (void)
+static struct stat *get_pidstat(const pid_t pid, const char *filename)
 {
-  const FILE_DSC *file;
-  const ITEM_DSC *item;
-  FILE *f;
-  const struct passwd *pw;
-  const char *user, *scan;
-  char tmp[10], *path, comm[COMM_LEN + 1];
-  int length, header, first, dummy, last_namelen = 0;
-  header = 1;
-  for (file = files; file; file = file->next)
-    if (file->name && (file->items || all))
-      {
-       if (header && (file->flags & FLAG_VERB))
-         {
-           fprintf (stderr, _("\n%*s USER        PID ACCESS COMMAND\n"),
-                    NAME_FIELD, "");
-           header = 0;
-         }
-       length = 0;
-       for (scan = file->name; scan && *scan; scan++)
-         if (*scan == '\\')
-           length += fprintf (stderr, "\\\\");
-         else if (*scan > ' ' && *scan <= '~')
-           {
-             putc(*scan,stderr);
-             length++;
-           }
-         else
-           length += fprintf (stderr, "\\%03o", *scan);
-       if (file->name_space)
-         length += fprintf (stderr, "/%s", file->name_space->name);
-
-       if (length > 0)
-         last_namelen=length;
+       char pathname[256];
+       struct stat *st;
+
+       if ( (st = malloc(sizeof(struct stat))) == NULL)
+               return NULL;
+       snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
+       if (stat(pathname, st) != 0) 
+               return NULL;
        else
-         fprintf(stderr, "\n%*.*s",last_namelen,last_namelen," ");
-
-       if (!(file->flags & FLAG_VERB))
-         {
-           putc (':',stderr);
-           length++;
-         }
-
-       first = 1;
-       for (item = file->items; item; item = item->next)
-         {
-           if (!(file->flags & FLAG_VERB))
-             {
-               if (item->type != it_proc)
-                 continue;
-        if ((first==1) && (item->u.proc.ref_set & (REF_FILE|REF_ROOT|REF_CWD|REF_EXE|REF_MMAP))) {
-    while (length < NAME_FIELD)
-    {
-      putc(' ',stderr);
-      length++;
-    }
-        }
-               printf ("%6d", item->u.proc.pid);
-        fflush(stdout);
-               /* if (item->u.proc.ref_set & REF_FILE)*/
-               if (item->u.proc.ref_set & REF_ROOT)
-                 putc ('r', stderr);
-               if (item->u.proc.ref_set & REF_CWD)
-                 putc ('c', stderr);
-               if (item->u.proc.ref_set & REF_EXE)
-                 putc ('e', stderr);
-               else if (item->u.proc.ref_set & REF_MMAP)
-                 putc ('m', stderr);
-               if ((file->flags & FLAG_UID) && item->u.proc.uid !=
-                   UID_UNKNOWN)
-                {
-                 if ((pw = getpwuid (item->u.proc.uid)) != NULL) {
-                   fprintf (stderr, "(%s)", pw->pw_name);
-                  } else {
-                   fprintf (stderr, "(%d)", item->u.proc.uid);
-                  }
-                }
-               first = 0;
-             }
-           else
-             {
-               const char *name;
-               int uid;
-
-               switch (item->type)
-                 {
-                 case it_proc:
-                   asprintf (&path, PROC_BASE "/%d/stat", item->u.proc.pid);
-                   strcpy (comm, "???");
-                   if ((f = fopen (path, "r")) != NULL)
-                     {
-                       (void) fscanf (f, "%d (%[^)]", &dummy, comm);
-                       (void) fclose (f);
-                     }
-                   free (path);
-                   name = comm;
-                   uid = item->u.proc.uid;
-                   break;
-                 case it_mount:
-                 case it_loop:
-                 case it_swap:
-                   name = item->u.misc.path;
-                   uid = 0;
-                   break;
-                 default:
-                   fprintf (stderr, _("Internal error (type %d)\n"),
-                            item->type);
-                   exit (1);
-                 }
-               if (uid == UID_UNKNOWN)
-                 user = "???";
-               else if ((pw = getpwuid (uid)) != NULL)
-                 user = pw->pw_name;
-               else
-                 {
-                   sprintf (tmp, "%d", uid);
-                   user = tmp;
-                 }
-               if (!first)
-                 fprintf (stderr, "%*s", NAME_FIELD, "");
-               else if (length > NAME_FIELD)
-                 fprintf (stderr, "\n%*s", NAME_FIELD, "");
-        else
-          while (length < NAME_FIELD)
-          {
-            putc(' ', stderr);
-            length++;
-          }
-               fprintf (stderr, " %-8s ", user);
-               switch (item->type)
-                 {
-                 case it_proc:
-                   printf ("%6d", item->u.proc.pid);
-            fflush(stdout);
-            fprintf (stderr, " %c%c%c%c%c  ",
-                           item->u.proc.ref_set & REF_FILE ? 'f' : '.',
-                           item->u.proc.ref_set & REF_ROOT ? 'r' : '.',
-                           item->u.proc.ref_set & REF_CWD ? 'c' : '.',
-                           item->u.proc.ref_set & REF_EXE ? 'e' : '.',
-                           (item->u.proc.ref_set & REF_MMAP) &&
-                           !(item->u.proc.ref_set & REF_EXE) ? 'm' : '.');
-                   break;
-                 case it_mount:
-                   fprintf (stderr, _("kernel mount  "));
-                   break;
-                 case it_loop:
-                   fprintf (stderr, _("kernel loop   "));
-                   break;
-                 case it_swap:
-                   fprintf (stderr, _("kernel swap   "));
-                   break;
-                 }
-               if (name)
-                {
-                 for (scan = name; *scan; scan++)
-                   if (*scan == '\\')
-                     fprintf (stderr, "\\\\");
-                   else if (*scan > ' ' && *scan <= '~')
-                     putc (*scan,stderr);
-                   else
-                     fprintf (stderr, "\\%03o", (unsigned char) *scan);
-                }
-               putc ('\n',stderr);
-             }
-           first = 0;
-         }
-       if (!(file->flags & FLAG_VERB) || first)
-         putc('\n',stderr);
-       if (file->flags & FLAG_KILL)
-         for (item = file->items; item; item = item->next)
-           kill_item (file, item);
-      }
+               return st;
 }
 
-
-static void
-kill_files (void)
+static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
 {
-  const FILE_DSC *file;
-  const ITEM_DSC *item;
+       char *dirpath, *filepath;
+       DIR *dirp;
+       struct dirent *direntry;
+       struct inode_list *ino_tmp;
+       struct device_list *dev_tmp;
+       struct stat st;
+
+       if ( (dirpath = malloc(MAX_PATHNAME)) == NULL)
+               return;
+       if ( (filepath = malloc(MAX_PATHNAME)) == NULL)
+               return;
+
+       snprintf(dirpath, MAX_PATHNAME, "/proc/%d/%s", pid, dirname);
+       if ( (dirp = opendir(dirpath)) == NULL)
+               return;
+       while ( (direntry = readdir(dirp)) != NULL) {
+               if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
+                       continue;
 
-  for (file = files; file; file = file->next)
-    if (file->flags & FLAG_KILL)
-      for (item = file->items; item; item = item->next)
-       kill_item (file, item);
+               snprintf(filepath, MAX_PATHNAME, "/proc/%d/%s/%s",
+                       pid, dirname, direntry->d_name);
+               if (stat(filepath, &st) != 0) {
+                       fprintf(stderr, "Cannot stat file %s: %s\n",filepath, strerror(errno));
+               } else {
+                       for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
+                               if (st.st_dev == dev_tmp->device)
+                                       add_matched_proc(dev_tmp->name, pid,uid, access);
+                       }
+                       for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
+                               if (st.st_dev == ino_tmp->device && st.st_ino == ino_tmp->inode)
+                                       add_matched_proc(ino_tmp->name, pid,uid, access);
+                       }
+               }
+       } /* while fd_dent */
+       closedir(dirp);
 }
 
-
-static void
-enter_item (const char *name, int flags, int sig_number, dev_t dev,
-           ino_t ino, SPACE_DSC * name_space)
+static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
 {
-  static FILE_DSC *last = NULL;
-  FILE_DSC *new;
-
-  if (!(new = malloc (sizeof (FILE_DSC))))
-    {
-      perror ("malloc");
-      exit (1);
-    }
-  if (last_named && !strcmp (last_named->name, name) &&
-      last_named->name_space == name_space)
-    new->name = NULL;
-  else if (!(new->name = strdup (name)))
-    {
-      perror ("strdup");
-      exit (1);
-    }
-  new->flags = flags;
-  new->sig_num = sig_number;
-  new->items = NULL;
-  new->next = NULL;
-  new->dev = dev;
-  new->ino = ino;
-  new->name_space = name_space;
-  if (last)
-    last->next = new;
-  else
-    files = new;
-  last = new;
-  new->named = last_named;
-  if (new->name)
-    last_named = new;
+       char pathname[MAX_PATHNAME];
+       char line[BUFSIZ];
+       struct inode_list *ino_tmp;
+       struct device_list *dev_tmp;
+       FILE *fp;
+       unsigned long long tmp_inode;
+       unsigned int tmp_maj, tmp_min;
+       dev_t tmp_device;
+
+       snprintf(pathname, MAX_PATHNAME, "/proc/%d/%s", pid, filename);
+       if ( (fp = fopen(pathname, "r")) == NULL)
+               return;
+       while (fgets(line,BUFSIZ, fp)) {
+               if (sscanf(line, "%*s %*s %*s %x:%x %lld", 
+                                       &tmp_maj, &tmp_min, &tmp_inode) == 3) {
+                       tmp_device = tmp_maj * 256 + tmp_min;
+                       for(dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next)
+                               if (dev_tmp->device == tmp_device)
+                                       add_matched_proc(dev_tmp->name, pid, uid, access);
+                       for(ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next)
+                               if (ino_tmp->device == tmp_device && ino_tmp->inode == tmp_inode)
+                                       add_matched_proc(ino_tmp->name, pid, uid, access);
+               }
+       }
+       fclose(fp);
 }
 
-
-static int
-parse_inet (const char *spec, const char *name_space, int *lcl_port,
-           struct sockaddr_storage *rmt_addr, int *rmt_port)
+static uid_t getpiduid(const pid_t pid)
 {
-  char *s, *here, *next, *end;
-  int port, field, address_match;
-
-  if (!(s = strdup (spec)))
-    {
-      perror ("strdup");
-      exit (1);
-    }
-  *lcl_port = *rmt_port = -1;
-  memset(rmt_addr, 0, sizeof(struct sockaddr_storage));
-  field = 0;
-  address_match = 0;
-  for (here = s; here; here = next ? next + 1 : NULL)
-    {
-      next = strchr (here, ',');
-      if (next)
-       *next = 0;
-      switch (field)
-       {
-       case 0:
-         /* fall through */
-       case 2:
-         if (!*here)
-           break;
-         port = strtoul (here, &end, 0);
-         if (*end)
-           {
-             struct servent *se;
-
-             if (!(se = getservbyname (here, name_space)))
+       char pathname[MAX_PATHNAME];
+       struct stat st;
+
+       if (snprintf(pathname, MAX_PATHNAME, "/proc/%d", pid) < 0) 
                return 0;
-             port = ntohs (se->s_port);
-           }
-         if (field)
-           *rmt_port = port;
-         else
-           *lcl_port = port;
-         break;
-       case 1:
-         if (!*here)
-           break;
-          if (!ipv4only) {
-
-            if (inet_pton(AF_INET6, here, &((struct sockaddr_in6*)rmt_addr)->sin6_addr) > 0) {
-              address_match = 1;
-              rmt_addr->ss_family = AF_INET6;
-             }
-          }
-          if (!ipv6only && !address_match) {
-            if (inet_pton(AF_INET, here, &((struct sockaddr_in*)rmt_addr)->sin_addr) > 0) {
-              address_match = 1;
-              rmt_addr->ss_family = AF_INET6;
-            }
-          }
-            
-         break;
-       default:
-         return 0;
-       }
-      field++;
-    }
-  return 1;
+       if (stat(pathname, &st) != 0)
+               return 0;
+       return st.st_uid;
 }
 
-static void find_net_dev(void)
+void add_mount_device(struct mountdev_list **mount_head,const char *fsname, const char *dir, dev_t device)
 {
-  int fd = socket(PF_INET, SOCK_DGRAM,0);
-  struct stat buf;
-  if (fd >= 0 && fstat(fd, &buf) == 0) {
-    net_dev = buf.st_dev;
-    close(fd);
-    return;
-  }
-  if (fd >= 0)
-    close(fd);
-  fprintf(stderr,_("can't find sockets' device number"));
+       struct mountdev_list *newmount;
+       /*printf("Adding mount Path: %s Dir:%s dev:%0x\n",dir, fsname, device);*/
+
+       if ( (newmount = malloc(sizeof(struct mountdev_list))) == NULL)
+               return;
+       newmount->fsname = strdup(fsname);
+       newmount->dir = strdup(dir);
+       newmount->device = device;
+       newmount->next = *mount_head;
+       *mount_head = newmount;
 }
 
-
-
-static void
-usage (void)
+/*
+ * scan_mount_devices : Create a list of mount points and devices
+ *   This list is used later for matching purposes
+ */
+void scan_mount_devices(const opt_type opts, struct mountdev_list **mount_devices)
 {
-  fprintf (stderr, _(
-    "Usage: fuser [ -a | -s | -c ] [ -n SPACE ] [ -SIGNAL ] [ -kimuv ] NAME...\n"
-    "             [ - ] [ -n SPACE ] [ -SIGNAL ] [ -kimuv ] NAME...\n"
-    "       fuser -l\n"
-    "       fuser -V\n"
-    "Show which processes use the named files, sockets, or filesystems.\n\n "
-    "    -a        display unused files too\n"
-    "    -c        mounted FS\n"
-    "    -f        silently ignored (for POSIX compatibility)\n"
-    "    -i        ask before killing (ignored without -k)\n"
-    "    -k        kill processes accessing the named file\n"
-    "    -l        list available signal names\n"
-    "    -m        show all processes using the named filesystems\n"
-    "    -n SPACE  search in this name space (file, udp, or tcp)\n"
-    "    -s        silent operation\n"
-    "    -SIGNAL   send this signal instead of SIGKILL\n"
-    "    -u        display user IDs\n"
-    "    -v        verbose output\n"
-    "    -V        display version information\n"
-    "    -4        search IPv4 sockets only\n"
-    "    -6        search IPv6 sockets only\n"
-    "    -         reset options\n\n"
-    "  udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
-  exit (1);
+       FILE *mntfp;
+       struct mntent *mnt_ptr;
+       struct stat st;
+       
+       if ( (mntfp = setmntent("/etc/mtab","r")) == NULL) {
+               fprintf(stderr, "Cannot open /etc/mtab: %s\n",
+                               strerror(errno));
+               return;
+       }
+       while ( (mnt_ptr = getmntent(mntfp)) != NULL) {
+               if (stat(mnt_ptr->mnt_dir, &st) == 0) {
+                       add_mount_device(mount_devices, mnt_ptr->mnt_fsname, mnt_ptr->mnt_dir, st.st_dev);
+               }
+       }
 }
 
-void print_version()
+static dev_t get_netdev(void)
 {
-  fprintf(stderr, _("fuser (PSmisc) %s\n"), VERSION);
-  fprintf(stderr, _(
-    "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
-  fprintf(stderr, _(
-    "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
-    "This is free software, and you are welcome to redistribute it under\n"
-    "the terms of the GNU General Public License.\n"
-    "For more information about these matters, see the files named COPYING.\n"));
+       int skt;
+       struct stat st;
+
+       if ( (skt = socket(PF_INET,SOCK_DGRAM,0)) < 0)
+               return -1;
+       if ( fstat(skt, &st) != 0) 
+               return -1;
+       return st.st_dev;
 }
 
-
-
-int
-main (int argc, char **argv)
+static void debug_match_lists(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head)
 {
-  SPACE_DSC *name_space;
-  int flags, silent, do_kill, sig_number, no_files;
-
-  flags = silent = do_kill = 0;
-  sig_number = SIGKILL;
-  name_space = name_spaces;
-  no_files = 1;
-
-  /* Setup the i18n */
-#ifdef ENABLE_NLS
-  setlocale(LC_ALL, "");
-  bindtextdomain(PACKAGE, LOCALEDIR);
-  textdomain(PACKAGE);
-#endif
+       struct names *nptr;
+       struct inode_list *iptr;
+       struct device_list *dptr;
 
-  if (argc < 2)
-    usage ();
-  if (argc == 2 && !strcmp (argv[1], "-l"))
-    {
-      list_signals ();
-      return 0;
-    }
-  find_net_dev();
-  while (--argc)
-    {
-      argv++;
-      if (**argv == '-')
-       if (!argv[0][1])
-         {
-           flags = 0;
-           sig_number = SIGKILL;
-         }
-       else
-         while (*++*argv)
-           {
-             int end;
-
-             end = 0;
-             switch (**argv)
-               {
-               case 'a':
-                 all = 1;
-                 break;
-        case 'f':
-          break;
-               case 'k':
-                 flags |= FLAG_KILL;
-                 do_kill = 1;
-                 break;
-               case 'i':
-                 flags |= FLAG_ASK;
-                 break;
-               case 'm':
-               case 'c':
-                 flags |= FLAG_DEV;
-                 break;
-               case 'n':
-                 if (!--argc)
-                   usage ();
-                 argv++;
-                 for (name_space = name_spaces; name_space->name;
-                      name_space++)
-                   if (!strcmp (*argv, name_space->name))
-                     break;
-                 if (!name_space->name)
-                   usage ();
-                 end = 1;
-                 break;
-               case 's':
-                 silent = 1;
-                 break;
-               case 'u':
-                 flags |= FLAG_UID;
-                 break;
-               case 'v':
-                 flags |= FLAG_VERB;
-                 break;
-               case 'V':
-                 print_version();
-                 return 0;
-                case '4':
-                    if (ipv6only) 
-                      usage();
-                    ipv4only = 1;
-                    break;
-                case '6':
-                    if (ipv4only)
-                      usage();
-                    ipv6only = 1;
-                    break;
-               default:
-                 if (isupper (**argv) || isdigit (**argv))
-                   {
-                     sig_number = get_signal (*argv, "fuser");
-                     argv[0][1] = 0;
-                     break;
-                   }
-                 usage ();
-               }
-             if (end)
-               break;
-           }
-      else
+       fprintf(stderr,"Names:\n");
+       for (nptr=names_head; nptr!= NULL; nptr=nptr->next) 
+       {
+               fprintf(stderr, "\t%s %c\n", nptr->filename, nptr->name_space);
+       }
+       fprintf(stderr,"\nInodes:\n");
+       for (iptr=ino_head; iptr!=NULL; iptr=iptr->next)
+       {
+               fprintf(stderr, "\tDev:%0lx Inode:%0lx\n",
+                               (unsigned long)iptr->device, (unsigned long)iptr->inode);
+       }
+       fprintf(stderr,"\nDevices:\n");
+       for (dptr=dev_head; dptr!=NULL; dptr=dptr->next)
        {
-         SPACE_DSC *this_name_space;
-         struct stat st;
-         char *here;
-
-         no_files = 0;
-         last_named = NULL;
-         this_name_space = name_space;
-         if (name_space != name_spaces || stat (*argv, &st) < 0)
-           {
-             here = strchr (*argv, '/');
-             if (here && here != *argv)
-               {
-                 for (this_name_space = name_spaces; this_name_space->name;
-                      this_name_space++)
-                   if (!strcmp (here + 1, this_name_space->name))
-                     {
-                       *here = 0;
-                       break;
-                     }
-                 if (!this_name_space->name)
-                   this_name_space = name_spaces;
+               fprintf(stderr, "\tDev:%0lx\n",
+                               (unsigned long)dptr->device);
+       }
+}
+
+/* 0 = no, 1=yes */
+static int ask(const pid_t pid)
+{
+       int c, res;
+       size_t len = 0;
+       char *line = NULL;
+
+       fflush(stdout);
+       while(1) {
+               fprintf(stderr, _("Kill process %d ? (y/N) "), pid);
+               fflush(stderr);
+               if (getline(&line, &len, stdin) < 0)
+                       return 0;
+               if (line[0] == '\n') {
+                       free(line);
+                       return 0;
                }
-           }
-         if (this_name_space == name_spaces)
-           {
-             if (stat (*argv, &st) < 0)
-               {
-                 perror (*argv);
-                 continue;
+               res = rpmatch(line);
+               if (res >= 0) {
+                       free(line);
+                       return res;
                }
-             if (flags & FLAG_DEV)
-              {
-               if (S_ISBLK (st.st_mode))
-                 st.st_dev = st.st_rdev;
-               else if (S_ISDIR (st.st_mode))
-                 {
-                   if (stat (*argv, &st) < 0)
-                     {
-                       perror (*argv);
+       } /* while */
+}
+
+static void kill_matched_proc(struct procs *proc_head, const opt_type opts)
+{
+       struct procs *pptr;
+
+       for (pptr = proc_head ; pptr != NULL ; pptr = pptr->next ) {
+               if ( (opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
                        continue;
-                     }
-                 }
-              }
-             if (S_ISSOCK (st.st_mode) || (flags & FLAG_DEV))
-               fill_unix_cache ();
-             if (!S_ISSOCK (st.st_mode) || (flags & FLAG_DEV))
-               enter_item (*argv, flags, sig_number, st.st_dev, st.st_ino,
-                           NULL);
-             else
-               {
-                 UNIX_CACHE *walk;
-
-                 for (walk = unix_cache; walk; walk = walk->next)
-                   if (walk->fs_dev == st.st_dev && walk->fs_ino ==
-                       st.st_ino)
-                     enter_item (*argv, flags, sig_number, net_dev,
-                        walk->net_ino, NULL);
-               }
-           }
-         else
-           {
-             NET_CACHE *walk;
-             struct sockaddr_storage rmt_addr;
-             int lcl_port, rmt_port;
-
-             if (flags & FLAG_DEV)
-               {
-                 fprintf (stderr, _("ignoring -m in name space \"%s\"\n"),
-                          this_name_space->name);
-                 flags &= ~FLAG_DEV;
-               }
-             fill_net_cache (this_name_space);
-             if (!parse_inet (*argv, this_name_space->name, &lcl_port,
-                              &rmt_addr, &rmt_port))
-               {
-                 fprintf (stderr, _("%s/%s: invalid specification\n"), *argv,
-                          this_name_space->name);
-                 continue;
-               }
-             for (walk = this_name_space->cache; walk; walk = walk->next)
-               if ((lcl_port == -1 || walk->lcl_port == lcl_port) &&
-                   (rmt_addr.ss_family == 0 || ( memcmp(
-                     &((struct sockaddr_in6*)&walk->rmt_addr)->sin6_addr,
-                     &((struct sockaddr_in6*)&rmt_addr)->sin6_addr,
-                     sizeof(struct in6_addr)) == 0) ) &&
-                   (rmt_port == -1 || walk->rmt_port == rmt_port))
-                 enter_item (*argv, flags, sig_number, net_dev, walk->ino,
-                             this_name_space);
-           }
+               fprintf(stderr, "debug killing proc %d\n", pptr->pid);
        }
-    }
-  if (no_files || (all && silent))
-    usage ();
-  scan_fd ();
-  scan_mounts ();
-  scan_swaps ();
-  if (do_kill && seteuid (getuid ()) < 0)
-    {
-      perror ("seteuid");
-      return 1;
-    }
-  self = getpid ();
-  if (silent)
-    kill_files ();
-  else
-    show_files_or_kill ();
-  return found_item ? 0 : 1;
 }
diff --git a/src/fusernew.c b/src/fusernew.c
deleted file mode 100644 (file)
index 131a944..0000000
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * fuser.c - identify processes using files
- *
- * Based on fuser.c Copyright (C) 1993-2005 Werner Almesberger and Craig Small
- *
- * Completely re-written
- * Copyright (C) 2005 Craig Small
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <pwd.h>
-#include <netdb.h>
-#include <getopt.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <mntent.h>
-
-#include "fuser.h"
-#include "i18n.h"
-
-#define NAME_FIELD 20          /* space reserved for file name */
-/* Function defines */
-static void add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid, const char access);
-static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access);
-static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access);
-static struct stat *get_pidstat(const pid_t pid, const char *filename);
-static uid_t getpiduid(const pid_t pid);
-static void print_matches(struct names *names_head, const opt_type opts);
-static void kill_matched_proc(struct procs *pptr, const opt_type opts);
-
-static dev_t get_netdev(void);
-int parse_mount(struct names *this_name, struct device_list **dev_list);
-static void add_device(struct device_list **dev_list, struct names  *this_name, dev_t device);
-void scan_mount_devices(const opt_type opts, struct mountdev_list **mount_devices);
-static void debug_match_lists(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head);
-
-static void usage (const char *errormsg)
-{
-       if (errormsg != NULL)
-               fprintf(stderr, "%s\n", errormsg);
-
-  fprintf (stderr, _(
-    "usage: fuser [ -a | -s | -c ] [ -n space ] [ -signal ] [ -kimuv ] name ...\n"
-    "             [ - ] [ -n space ] [ -signal ] [ -kimuv ] name ...\n"
-    "       fuser -l\n"
-    "       fuser -V\n\n"
-    "    -a        display unused files too\n"
-    "    -c        mounted FS\n"
-    "    -f        silently ignored (for POSIX compatibility)\n"
-    "    -k        kill processes accessing that file\n"
-    "    -i        ask before killing (ignored without -k)\n"
-    "    -l        list signal names\n"
-    "    -m        mounted FS\n"
-    "    -n space  search in the specified name space (file, udp, or tcp)\n"
-    "    -s        silent operation\n"
-    "    -signal   send signal instead of SIGKILL\n"
-    "    -u        display user ids\n"
-    "    -v        verbose output\n"
-    "    -V        display version information\n"
-    "    -4        search IPv4 sockets only\n"
-    "    -6        search IPv6 sockets only\n"
-    "    -         reset options\n\n"
-    "  udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
-  exit (1);
-}
-
-void print_version()
-{
-  fprintf(stderr, _("fuser (psmisc) %s\n"), VERSION);
-  fprintf(stderr, _(
-    "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
-  fprintf(stderr, _(
-    "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
-    "This is free software, and you are welcome to redistribute it under\n"
-    "the terms of the GNU General Public License.\n"
-    "For more information about these matters, see the files named COPYING.\n"));
-}
-
-static void scan_procs(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head)
-{
-       DIR *topproc_dir;
-       struct dirent *topproc_dent;
-       char *fd_dirpath, *fd_pathname;
-       struct inode_list *ino_tmp;
-       struct device_list *dev_tmp;
-       pid_t pid, my_pid;
-       uid_t uid;
-       struct stat *cwd_stat, *exe_stat, *root_stat;
-
-       if ( (fd_dirpath = malloc(MAX_PATHNAME)) == NULL)
-               return;
-       if ( (fd_pathname = malloc(MAX_PATHNAME)) == NULL)
-               return;
-
-       if ( (topproc_dir = opendir("/proc")) == NULL) {
-               fprintf(stderr, "Cannot open /proc directory: %s\n", strerror(errno));
-               exit(1);
-       }
-       my_pid = getpid();
-       while ( (topproc_dent = readdir(topproc_dir)) != NULL) {
-               if (topproc_dent->d_name[0] < '0' || topproc_dent->d_name[0] > '9') /* Not a process */
-                       continue;
-               pid = atoi(topproc_dent->d_name);
-               /* Dont print myself */
-               if (pid == my_pid)
-                       continue;
-               uid = getpiduid(pid);
-
-               root_stat = get_pidstat(pid, "root");
-               cwd_stat = get_pidstat(pid, "cwd");
-               exe_stat = get_pidstat(pid, "exe");
-               /* Scan the devices */
-               for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
-                       if (exe_stat != NULL && exe_stat->st_dev == dev_tmp->device) 
-                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_EXE);
-                       if (root_stat != NULL && root_stat->st_dev == dev_tmp->device) 
-                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_ROOT);
-                       if (cwd_stat != NULL && cwd_stat->st_dev == dev_tmp->device) 
-                               add_matched_proc(dev_tmp->name, pid, uid, ACCESS_CWD);
-               }
-               for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
-                       if (exe_stat != NULL) {
-                               if (exe_stat->st_dev == ino_tmp->device && exe_stat->st_ino == ino_tmp->inode) {
-                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_EXE);
-                               }
-                       }
-                       if (root_stat != NULL) {
-                               if (root_stat->st_dev == ino_tmp->device && root_stat->st_ino == ino_tmp->inode){
-                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_ROOT);
-                               }
-
-                       }
-                       if (cwd_stat != NULL){
-                               if (cwd_stat->st_dev == ino_tmp->device && cwd_stat->st_ino == ino_tmp->inode) {
-                                       add_matched_proc(ino_tmp->name, pid, uid, ACCESS_CWD);
-                               }
-                       }
-               }
-               check_dir(pid, "lib", dev_head, ino_head, uid, ACCESS_MMAP);
-               check_dir(pid, "mmap", dev_head, ino_head, uid, ACCESS_MMAP);
-               check_dir(pid, "fd", dev_head, ino_head, uid, ACCESS_FILE);
-               check_map(pid, "maps", dev_head, ino_head, uid, ACCESS_MMAP);
-
-       } /* while topproc_dent */
-       closedir(topproc_dir);
-}
-static void add_inode(struct inode_list **ino_list, struct names  *this_name, dev_t device, ino_t inode)
-{
-       struct inode_list *ino_tmp, *ino_head;
-
-       ino_head = *ino_list;
-
-       if ( (ino_tmp = malloc(sizeof(struct inode_list))) == NULL)
-               return;
-       ino_tmp->name = this_name;
-       ino_tmp->device = device;
-       ino_tmp->inode = inode;
-       ino_tmp->next = ino_head;
-       *ino_list = ino_tmp;
-}
-
-static void add_device(struct device_list **dev_list, struct names  *this_name, dev_t device)
-{
-       struct device_list *dev_tmp, *dev_head;
-
-       /*printf("Adding device %s %d\n", this_name->filename, device);*/
-       dev_head = *dev_list;
-
-       if ( (dev_tmp = malloc(sizeof(struct device_list))) == NULL)
-               return;
-       dev_tmp->name = this_name;
-       dev_tmp->device = device;
-       dev_tmp->next = dev_head;
-       *dev_list = dev_tmp;
-}
-
-static void add_ip_conn(struct ip_connections **ip_list, const char *protocol, struct names *this_name, const int lcl_port, const int rmt_port, unsigned long rmt_address)
-{
-       struct ip_connections *ip_tmp, *ip_head;
-
-       ip_head = *ip_list;
-
-       if ( (ip_tmp = malloc(sizeof(struct ip_connections))) == NULL)
-               return;
-       ip_tmp->name = this_name;
-       ip_tmp->lcl_port = lcl_port;
-       ip_tmp->rmt_port = rmt_port;
-       ip_tmp->rmt_address.s_addr = rmt_address;
-       ip_tmp->next = ip_head;
-
-       *ip_list = ip_tmp;
-}
-
-static void add_ip6_conn(struct ip6_connections **ip_list, const char *protocol, struct names *this_name, const int lcl_port, const int rmt_port, struct in6_addr rmt_address)
-{
-       struct ip6_connections *ip_tmp, *ip_head;
-
-       ip_head = *ip_list;
-
-       if ( (ip_tmp = malloc(sizeof(struct ip6_connections))) == NULL)
-               return;
-       ip_tmp->name = this_name;
-       ip_tmp->lcl_port = lcl_port;
-       ip_tmp->rmt_port = rmt_port;
-       memcpy(&(ip_tmp->rmt_port),&(rmt_port),sizeof(struct in6_addr));
-       ip_tmp->next = ip_head;
-
-       *ip_list = ip_tmp;
-}
-
-static void add_matched_proc(struct names *name_list, const pid_t pid, const uid_t uid, const char access)
-{
-       struct procs *pptr, *last_proc;
-       char *pathname;
-       char cmdname[101], *cptr;
-       int cmdlen;
-       FILE *fp;
-
-       last_proc = NULL;
-       for (pptr = name_list->matched_procs; pptr != NULL ; pptr = pptr->next)
-       {
-               last_proc = pptr;
-               if (pptr->pid == pid) {
-                       pptr->access |= access;
-                       return;
-               }
-       }
-       /* Not found */
-       if ( (pptr = malloc(sizeof (struct procs))) == NULL) {
-               fprintf(stderr,_("Cannot allocate memory for matched proc: %s\n"), strerror(errno));
-               return;
-       }
-       pptr->pid = pid;
-       pptr->uid = uid;
-       pptr->access = access;
-       pptr->next = NULL;
-       /* set command name */
-       pptr->command = NULL;
-       if ( (asprintf(&pathname, "/proc/%d/stat", pid) > 0) &&
-                       ( (fp = fopen(pathname, "r")) != NULL) &&
-                       ( fscanf(fp, "%*d (%100[^)]", cmdname) == 1)) 
-               if ( (pptr->command = malloc(MAX_CMDNAME+1)) != NULL) {
-                       cmdlen = 0;
-                       for (cptr = cmdname; cmdlen < MAX_CMDNAME && *cptr ; cptr++) {
-                               if (isprint(*cptr))
-                                       pptr->command[cmdlen++] = *cptr;
-                               else if(cmdlen < (MAX_CMDNAME-4))
-                                       cmdlen += sprintf(&(pptr->command[cmdlen]), "\\%03o", *cptr);
-                       }
-                       pptr->command[cmdlen] = '\0';
-               }
-       if (last_proc == NULL)
-               name_list->matched_procs = pptr;
-       else
-               last_proc->next = pptr;
-}
-
-int parse_mount(struct names *this_name, struct device_list **dev_list)
-{
-       struct stat st;
-
-       if (stat(this_name->filename, &st) != 0) {
-               fprintf(stderr, "Cannot stat mount point %s: %s\n", 
-                               this_name->filename,
-                               strerror(errno));
-               exit(1);
-       }
-       /*printf("Debug: parse_mount() adding %s\n", this_name->filename);*/
-       add_device(dev_list, this_name, st.st_dev);
-       return 0;
-}
-
-int parse_file(struct names *this_name, struct inode_list **ino_list)
-{
-       struct stat st;
-
-       if (stat(this_name->filename, &st) != 0) {
-               fprintf(stderr,"Cannot stat %s: %s\n", this_name->filename,
-                               strerror(errno));
-               return -1;
-       }
-       /*printf("adding file %s %lX %lX\n", this_name->filename,
-                       (unsigned long)st.st_dev, (unsigned long)st.st_ino);*/
-       add_inode(ino_list, this_name, st.st_dev, st.st_ino);
-       return 0;
-}
-
-int parse_mounts(struct names *this_name, struct mountdev_list *mounts, struct device_list **dev_list, const char opts) 
-{
-       struct stat st;
-       struct mountdev_list *mountptr;
-       dev_t match_device;
-
-       if (stat(this_name->filename, &st) != 0) {
-               fprintf(stderr,"Cannot stat %s: %s\n", this_name->filename,
-                               strerror(errno));
-               return -1;
-       }
-       if (S_ISBLK(st.st_mode))
-               match_device = st.st_rdev;
-       else
-               match_device = st.st_dev;
-       for (mountptr = mounts ; mountptr != NULL ; mountptr = mountptr->next) {
-               if (mountptr->device == match_device) {
-                       /*printf("Debug: adding parse_mounts() adding %s\n", 
-                                       this_name->filename);*/
-                       add_device(dev_list, this_name, match_device);
-               }
-       }
-       return 0;
-}
-
-int parse_inet(struct names *this_name, const int ipv6_only, const int ipv4_only, struct ip_connections **ip_list, struct ip6_connections **ip6_list)
-{
-       struct addrinfo *res, *resptr;
-       struct addrinfo hints;
-       int errcode;
-       char *lcl_port_str, *rmt_addr_str, *rmt_port_str, *tmpstr, *tmpstr2;
-       in_port_t lcl_port;
-       struct sockaddr_in *sin;
-       struct sockaddr_in6 *sin6;
-       char hostspec[100];
-       char *protocol;
-       int i;
-       
-       if ( (protocol = strchr(this_name->filename, '/')) == NULL)
-               return -1;
-       protocol++;
-       if (protocol[0] == '\0')
-               return -1;
-       for (i=0; i < 99 && this_name->filename[i] != '\0' && this_name->filename[i] != '/'; i++)
-               hostspec[i] = this_name->filename[i];
-       hostspec[i] = '\0';
-
-       lcl_port_str = rmt_addr_str = rmt_port_str = NULL;
-       /* Split out the names */
-       if ( (tmpstr = strchr(hostspec, ',')) == NULL) {
-               /* Single option */
-               lcl_port_str = strdup(hostspec);
-       } else {
-               if (tmpstr == hostspec)
-                       lcl_port_str = NULL;
-               else {
-                       lcl_port_str = strdup(hostspec);
-                       *tmpstr = '\0';
-               }
-               tmpstr++;
-               if (*tmpstr != '\0') {
-                       if ( (tmpstr2 = strchr(tmpstr, ',')) == NULL) {
-                               /* Only 2 options */
-                               rmt_addr_str = tmpstr;
-                       } else {
-                               if (tmpstr2 == tmpstr)
-                                       rmt_addr_str = NULL;
-                               else {
-                                       rmt_addr_str = tmpstr;
-                                       *tmpstr2 = '\0';
-                               }
-                               tmpstr2++;
-                               if (*tmpstr2 != '\0')
-                                       rmt_port_str = tmpstr2;
-                       }
-               }
-       }
-       /*printf("parsed to lp %s rh %s rp %s\n", lcl_port_str, rmt_addr_str, rmt_port_str);*/
-
-       memset(&hints, 0, sizeof(hints));
-       if (ipv6_only) {
-               hints.ai_family = PF_INET6;
-       } else if (ipv4_only) {
-                       hints.ai_family = PF_INET;
-               } else 
-                       hints.ai_family = PF_UNSPEC;
-       if (strcmp(protocol, "tcp") == 0)
-               hints.ai_socktype = SOCK_STREAM;
-       else
-               hints.ai_socktype = SOCK_DGRAM;
-
-       if (lcl_port_str == NULL) {
-               lcl_port = 0;
-       } else {
-               /* Resolve local port first */
-               if ( (errcode = getaddrinfo(NULL, lcl_port_str, &hints, &res)) != 0) {
-                       fprintf(stderr, "Cannot resolve local port %s: %s\n",
-                                       lcl_port_str, gai_strerror(errcode));
-                       return -1;
-               }
-               if (res == NULL)
-                       return -1;
-               switch(res->ai_family) {
-                       case AF_INET:
-                               lcl_port = ((struct sockaddr_in*)(res->ai_addr))->sin_port;
-                               break;
-                       case AF_INET6:
-                               lcl_port = ((struct sockaddr_in6*)(res->ai_addr))->sin6_port;
-                               break;
-                       default:
-                               fprintf(stderr, "Uknown local port AF %d\n", res->ai_family);
-                               freeaddrinfo(res);
-                               return -1;
-               }
-               freeaddrinfo(res);
-       }
-       free(lcl_port_str);
-       res = NULL;
-       if (rmt_addr_str == NULL && rmt_port_str == NULL) {
-               add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), 0, INADDR_ANY);
-               add_ip6_conn(ip6_list, protocol,this_name, ntohs(lcl_port), 0, in6addr_any);
-               return 0;
-       } else {
-               /* Resolve remote address and port */
-               if (getaddrinfo(rmt_addr_str, rmt_port_str, &hints, &res) == 0) {
-                       for(resptr = res ; resptr != NULL ; resptr = resptr->ai_next ) {
-                               switch(resptr->ai_family) {
-                                       case AF_INET:
-                                               sin = (struct sockaddr_in*)resptr->ai_addr;
-                                               add_ip_conn(ip_list, protocol, this_name, ntohs(lcl_port), ntohs(sin->sin_port), sin->sin_addr.s_addr);
-                                       break;
-                               case AF_INET6:
-                                       sin6 = (struct sockaddr_in6*)resptr->ai_addr;
-                                               add_ip6_conn(ip6_list, protocol, this_name, ntohs(lcl_port), ntohs(sin6->sin6_port), sin6->sin6_addr);
-                                       break;
-                               }
-                       } /*while */
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-
-
-
-void find_net_sockets(struct inode_list **ino_list, struct ip_connections *conn_list, const char *protocol, dev_t netdev)
-{
-       FILE *fp;
-       char pathname[200], line[BUFSIZ];
-       unsigned long loc_port, rmt_port;
-       unsigned long rmt_addr;
-       ino_t inode;
-       struct ip_connections *conn_tmp;
-
-       if (snprintf(pathname,200, "/proc/net/%s", protocol) < 0) 
-               return ;
-
-       if ( (fp = fopen(pathname, "r")) == NULL) {
-               fprintf(stderr, "Cannot open protocol file: %s", strerror(errno));
-               return;
-       }
-       while (fgets(line, BUFSIZ, fp) != NULL) {
-               if (sscanf(line, "%*u: %*x:%lx %08lx:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
-                       &loc_port,
-                       &rmt_addr,
-                       &rmt_port,
-                       &inode) != 4)
-                       continue;
-               /*printf("Found *:%lu with %s:%lu\n", loc_port, inet_ntoa(*((struct in_addr*)&rmt_addr)), rmt_port);*/
-               for(conn_tmp = conn_list ; conn_tmp != NULL ; conn_tmp = conn_tmp->next) {
-                       /*printf("Comparing with *.%lu %s:%lu ...", 
-                                       conn_tmp->lcl_port,
-                                       inet_ntoa(conn_tmp->rmt_address),
-                                       conn_tmp->rmt_port);*/
-                       if (conn_tmp->lcl_port == loc_port &&
-                                       conn_tmp->rmt_port == rmt_port &&
-                                       (memcmp(&(conn_tmp->rmt_address), &(rmt_addr),4) ==0)
-                          ) {
-                               /* add inode to list */
-                               add_inode(ino_list, conn_tmp->name, netdev, inode);
-                       }
-               }
-                       
-
-       }
-       return ;
-}
-
-void find_net6_sockets(struct inode_list **ino_list, struct ip6_connections *conn_list, const char *protocol, const dev_t netdev)
-{
-       FILE *fp;
-       char pathname[200], line[BUFSIZ];
-       unsigned long loc_port, rmt_port;
-       struct in6_addr rmt_addr;
-       unsigned int tmp_addr[4];
-       char rmt_addr6str[INET6_ADDRSTRLEN];
-       struct ip6_connections *head, *tmpptr, *tail;
-       struct ip6_connections *conn_tmp;
-       ino_t inode;
-
-       head = tmpptr = tail = NULL;
-
-       if (snprintf(pathname,200, "/proc/net/%s6", protocol) < 0) 
-               return ;
-
-       if ( (fp = fopen(pathname, "r")) == NULL) {
-               fprintf(stderr, "Cannot open protocol file: %s", strerror(errno));
-               return ;
-       }
-       while (fgets(line, BUFSIZ, fp) != NULL) {
-               if (sscanf(line, "%*u: %*x:%lx %08x%08x%08x%08x:%lx %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
-                       &loc_port, 
-                       &(tmp_addr[0]),
-                       &(tmp_addr[1]),
-                       &(tmp_addr[2]),
-                       &(tmp_addr[3]),
-                       &rmt_port, &inode) != 7)
-                       continue;
-               rmt_addr.s6_addr32[0] = tmp_addr[0];
-               rmt_addr.s6_addr32[1] = tmp_addr[1];
-               rmt_addr.s6_addr32[2] = tmp_addr[2];
-               rmt_addr.s6_addr32[3] = tmp_addr[3];
-               inet_ntop(AF_INET6, &rmt_addr, rmt_addr6str, INET6_ADDRSTRLEN);
-               /*printf("Found %ld with %s:%ld\n", loc_port, rmt_addr6str, rmt_port);*/
-               for(conn_tmp = conn_list ; conn_tmp != NULL ; conn_tmp = conn_tmp->next) {
-                       inet_ntop(AF_INET6, &conn_tmp->rmt_address, rmt_addr6str, INET6_ADDRSTRLEN);
-               /*      printf("Comparing with *.%lu %s:%lu ...", 
-                                       conn_tmp->lcl_port,
-                                       rmt_addr6str,
-                                       conn_tmp->rmt_port);*/
-                       if (conn_tmp->lcl_port == loc_port &&
-                                       conn_tmp->rmt_port == rmt_port &&
-                                       (memcmp(&(conn_tmp->rmt_address), &(rmt_addr),16) ==0)
-                          ) {
-                               add_inode(ino_list, conn_tmp->name, netdev, inode);
-                       }
-               }
-       }
-}
-
-int main(int argc, char *argv[])
-{
-       static struct option long_options[] = {
-               {"all", 0, 0, 'a'},
-               {"mountpoint", 0, 0, 'c'},
-               {"help", 0, 0, 'h'},
-               {"interactive", 0, 0, 'i'},
-               {"kill", 0, 0, 'k'},
-               {"list", 0, 0, 'l'},
-               {"mounted", 0, 0, 'm'},
-               {"name-space", 1, 0, 'n'},
-               {"silent", 0, 0, 's'},
-               {"show-user", 0, 0, 'u'},
-               {"verbose", 0, 0, 'v'},
-               {"version", 0, 0, 'V'},
-               {0, 0, 0, 0}
-       };
-       opt_type opts;
-       int ipv4_only, ipv6_only;
-       unsigned char default_namespace = NAMESPACE_FILE;
-       struct mountdev_list *mount_devices = NULL;
-       struct device_list *match_devices = NULL;
-
-       dev_t netdev;
-       struct ip_connections *tcp_connection_list = NULL;
-       struct ip_connections *udp_connection_list = NULL;
-       struct ip6_connections *tcp6_connection_list = NULL;
-       struct ip6_connections *udp6_connection_list = NULL;
-       struct inode_list *match_inodes = NULL;
-       struct names *names_head, *this_name, *names_tail;
-       int optc, opti;
-       char *nsptr;
-
-       ipv4_only = ipv6_only = 0;
-       names_head = this_name = names_tail = NULL;
-       opts = 0;
-
-       netdev = get_netdev();
-       scan_mount_devices(opts, &mount_devices);
-
-       while ( (optc = getopt_long(argc, argv, "46acfhiklmn:suvV",
-                                       long_options, &opti)) != -1) {
-               switch(optc) {
-                       case '4':
-                               ipv4_only = 1;
-                               break;
-                       case '6':
-                               ipv6_only = 1;
-                               break;
-                       case 'a':
-                               opts |= OPT_ALLFILES;
-                               break;
-                       case 'c':
-                               opts |= OPT_MOUNTPOINT;
-                               break;
-                       case 'f':
-                               /* ignored */
-                               break;
-                       case 'h':
-                               usage(NULL);
-                               break;
-                       case 'i':
-                               opts |= OPT_INTERACTIVE;
-                               break;
-                       case 'k':
-                               opts |= OPT_KILL;
-                               break;
-                       case 'l':
-                               list_signals();
-                               return 0;
-                       case 'm':
-                               opts |= OPT_MOUNTS;
-                               break;
-                       case 'n':
-                               if (strcmp(optarg, "tcp") == 0)
-                                       default_namespace = NAMESPACE_TCP;
-                               else if (strcmp(optarg, "udp") == 0)
-                                       default_namespace = NAMESPACE_UDP;
-                               else if (strcmp(optarg, "file") == 0)
-                                       default_namespace = NAMESPACE_FILE;
-                               else 
-                                       usage(_("Invalid namespace name"));
-                               break;
-                       case 's':
-                               opts |= OPT_SILENT;
-                               break;
-                       case 'u':
-                               opts |= OPT_USER;
-                               break;
-                       case 'v':
-                               opts |= OPT_VERBOSE;
-                               break;
-                       case 'V':
-                               print_version();
-                               return 0;
-                       case '?':
-                               usage(NULL);
-                               break;
-               }
-
-       }
-       if (optind < argc) {
-               /* File specifications */
-               for( ; optind < argc ; optind++) {
-                       if ( (this_name = malloc(sizeof(struct names))) == NULL)
-                               continue;
-                       this_name->next = NULL;
-                       if (names_head == NULL)
-                               names_head = this_name;
-                       if (names_tail != NULL)
-                               names_tail->next = this_name;
-                       names_tail = this_name;
-                       /* try to find namespace spec */
-                       this_name->name_space = default_namespace;
-                       if ( ((nsptr = strchr(argv[optind], '/')) != NULL )
-                                       && ( nsptr != argv[optind] )) {
-                               if (strcmp(nsptr+1, "tcp") == 0) {
-                                       this_name->name_space = NAMESPACE_TCP;
-                                       *nsptr = '\0';
-                               } else if (strcmp(nsptr+1, "udp") == 0) {
-                                       this_name->name_space = NAMESPACE_UDP;
-                                       *nsptr = '\0';
-                               } else if (strcmp(nsptr+1, "file") == 0) {
-                                       this_name->name_space = NAMESPACE_FILE;
-                                       *nsptr = '\0';
-                               }
-                       }
-                       this_name->matched_procs = NULL;
-                       if ((opts & OPT_MOUNTPOINT) && this_name->name_space != NAMESPACE_FILE)
-                               usage(_("You can only use files with mountpoint option"));
-                       switch(this_name->name_space) {
-                               case NAMESPACE_TCP:
-                                       asprintf(&(this_name->filename), "%s/tcp", argv[optind]);
-                                       parse_inet(this_name, ipv4_only, ipv6_only, &tcp_connection_list, &tcp6_connection_list);
-                                       break;
-                               case NAMESPACE_UDP:
-                                       asprintf(&(this_name->filename), "%s/udp", argv[optind]);
-                                       parse_inet(this_name, ipv4_only, ipv6_only, &tcp_connection_list, &tcp6_connection_list);
-                                       break;
-                               default: /* FILE */
-                                       this_name->filename = strdup(argv[optind]);
-                                       parse_file(this_name, &match_inodes);
-                                       if (opts & OPT_MOUNTPOINT || opts & OPT_MOUNTS)
-                                       parse_mounts(this_name, mount_devices, &match_devices, opts);
-                                       break;
-                       }
-               } /* for */
-       } else {
-               usage(_("No process specification given"));
-       }
-       /* Check conflicting operations */
-       if (opts & OPT_MOUNTPOINT) {
-               if (opts & OPT_MOUNTS)
-                       usage(_("You cannot use the mounted and mountpoint flags together"));
-       }
-       if (opts & OPT_SILENT) 
-       {
-               opts &= ~OPT_VERBOSE;
-               opts &= ~OPT_USER;
-               if (opts & OPT_ALLFILES)
-                       usage(_("all option cannot be used with silent option."));
-       }
-       if (ipv4_only && ipv6_only)
-               usage(_("You cannot search for only IPv4 and only IPv6 sockets a the same time"));
-       if (!ipv4_only) {
-               if (tcp_connection_list != NULL)
-                       find_net_sockets(&match_inodes, tcp_connection_list, "tcp",netdev);
-               if (udp_connection_list != NULL)
-                       find_net_sockets(&match_inodes, udp_connection_list, "udp",netdev);
-       }
-       if (!ipv6_only) {
-               if (tcp6_connection_list != NULL)
-                       find_net6_sockets(&match_inodes, tcp6_connection_list, "tcp",netdev);
-               if (udp6_connection_list != NULL)
-                       find_net6_sockets(&match_inodes,  udp6_connection_list, "udp",netdev);
-       }
-       /*debug_match_lists(names_head, match_inodes, match_devices);*/
-       scan_procs(names_head, match_inodes, match_devices);
-       print_matches(names_head,opts);
-       return 0;
-}
-
-static void print_matches(struct names *names_head, const opt_type opts)
-{
-       struct names *nptr;
-       struct procs *pptr;
-       char first;
-       int len;
-       struct passwd *pwent = NULL;
-       
-       if (opts & OPT_VERBOSE)
-               fprintf(stderr, _("\n%*s USER        PID ACCESS COMMAND\n"),
-                               NAME_FIELD, "");
-       for (nptr = names_head; nptr != NULL ; nptr = nptr->next) {
-               fprintf(stderr, "%s", nptr->filename);
-               first = 1;
-               len = strlen(nptr->filename);
-               if (!(opts & OPT_VERBOSE)) {
-                       putc(':', stderr);
-                       len++;
-               }
-               for (pptr = nptr->matched_procs; pptr != NULL ; pptr = pptr->next) {
-                       if (opts & (OPT_VERBOSE|OPT_USER)) {
-                               if (pwent == NULL || pwent->pw_uid != pptr->uid)
-                                       pwent = getpwuid(pptr->uid);
-                       }
-                       if (len > NAME_FIELD && (opts & OPT_VERBOSE)) {
-                               putc('\n', stderr);
-                               len=0;
-                       }
-                       if ((opts & OPT_VERBOSE) || first) 
-                               while (len++ < NAME_FIELD)
-                                       putc(' ', stderr);
-                       if (opts & OPT_VERBOSE) {
-                               if (pwent == NULL)
-                                       fprintf(stderr, " %-8s ", _("(unknown)"));
-                               else
-                                       fprintf(stderr, " %-8s ", pwent->pw_name);
-                       }
-                       printf("%6d", pptr->pid);
-                       fflush(stdout);
-                       if (opts & OPT_VERBOSE) {
-                               fprintf(stderr, " %c%c%c%c%c ",
-                                               pptr->access & ACCESS_FILE ? 'f' : '.',
-                                               pptr->access & ACCESS_ROOT ? 'r' : '.',
-                                               pptr->access & ACCESS_CWD ? 'c' : '.',
-                                               pptr->access & ACCESS_EXE ? 'e' : '.',
-                                               (pptr->access & ACCESS_MMAP) && !(pptr->access & ACCESS_EXE) ? 'm' : '.');
-                       } else {
-                               if (pptr->access & ACCESS_ROOT)
-                                       putc('r', stderr);
-                               if (pptr->access & ACCESS_CWD)
-                                       putc('c', stderr);
-                               if (pptr->access & ACCESS_EXE)
-                                       putc('e', stderr);
-                               else if (pptr->access & ACCESS_MMAP)
-                                       putc('m', stderr);
-                       }
-                       if (opts & OPT_USER) {
-                               if (pwent == NULL)
-                                       fprintf(stderr, " %-8s ", _("(unknown)"));
-                               else
-                                       fprintf(stderr, "(%s)", pwent->pw_name);
-                       }
-                       if (opts & OPT_VERBOSE) {
-                               if (pptr->command == NULL)
-                                       fprintf(stderr, "???\n");
-                               else 
-                                       fprintf(stderr, "%s\n", pptr->command);
-                       }
-                       len = 0;
-                       first = 0;
-               }
-               if (nptr->matched_procs == NULL || !(opts & OPT_VERBOSE))
-                       putc('\n', stderr);
-               if (opts & OPT_KILL)
-                       kill_matched_proc(nptr->matched_procs,  opts);
-
-       } /* next name */
-
-}
-
-static struct stat *get_pidstat(const pid_t pid, const char *filename)
-{
-       char pathname[256];
-       struct stat *st;
-
-       if ( (st = malloc(sizeof(struct stat))) == NULL)
-               return NULL;
-       snprintf(pathname, 256, "/proc/%d/%s", pid, filename);
-       if (stat(pathname, st) != 0) 
-               return NULL;
-       else
-               return st;
-}
-
-static void check_dir(const pid_t pid, const char *dirname, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
-{
-       char *dirpath, *filepath;
-       DIR *dirp;
-       struct dirent *direntry;
-       struct inode_list *ino_tmp;
-       struct device_list *dev_tmp;
-       struct stat st;
-
-       if ( (dirpath = malloc(MAX_PATHNAME)) == NULL)
-               return;
-       if ( (filepath = malloc(MAX_PATHNAME)) == NULL)
-               return;
-
-       snprintf(dirpath, MAX_PATHNAME, "/proc/%d/%s", pid, dirname);
-       if ( (dirp = opendir(dirpath)) == NULL)
-               return;
-       while ( (direntry = readdir(dirp)) != NULL) {
-               if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9')
-                       continue;
-
-               snprintf(filepath, MAX_PATHNAME, "/proc/%d/%s/%s",
-                       pid, dirname, direntry->d_name);
-               if (stat(filepath, &st) != 0) {
-                       fprintf(stderr, "Cannot stat file %s: %s\n",filepath, strerror(errno));
-               } else {
-                       for (dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next) {
-                               if (st.st_dev == dev_tmp->device)
-                                       add_matched_proc(dev_tmp->name, pid,uid, access);
-                       }
-                       for (ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next) {
-                               if (st.st_dev == ino_tmp->device && st.st_ino == ino_tmp->inode)
-                                       add_matched_proc(ino_tmp->name, pid,uid, access);
-                       }
-               }
-       } /* while fd_dent */
-       closedir(dirp);
-}
-
-static void check_map(const pid_t pid, const char *filename, struct device_list *dev_head, struct inode_list *ino_head, const uid_t uid, const char access)
-{
-       char pathname[MAX_PATHNAME];
-       char line[BUFSIZ];
-       struct inode_list *ino_tmp;
-       struct device_list *dev_tmp;
-       FILE *fp;
-       unsigned long long tmp_inode;
-       unsigned int tmp_maj, tmp_min;
-       dev_t tmp_device;
-
-       snprintf(pathname, MAX_PATHNAME, "/proc/%d/%s", pid, filename);
-       if ( (fp = fopen(pathname, "r")) == NULL)
-               return;
-       while (fgets(line,BUFSIZ, fp)) {
-               if (sscanf(line, "%*s %*s %*s %x:%x %lld", 
-                                       &tmp_maj, &tmp_min, &tmp_inode) == 3) {
-                       tmp_device = tmp_maj * 256 + tmp_min;
-                       for(dev_tmp = dev_head ; dev_tmp != NULL ; dev_tmp = dev_tmp->next)
-                               if (dev_tmp->device == tmp_device)
-                                       add_matched_proc(dev_tmp->name, pid, uid, access);
-                       for(ino_tmp = ino_head ; ino_tmp != NULL ; ino_tmp = ino_tmp->next)
-                               if (ino_tmp->device == tmp_device && ino_tmp->inode == tmp_inode)
-                                       add_matched_proc(ino_tmp->name, pid, uid, access);
-               }
-       }
-       fclose(fp);
-}
-
-static uid_t getpiduid(const pid_t pid)
-{
-       char pathname[MAX_PATHNAME];
-       struct stat st;
-
-       if (snprintf(pathname, MAX_PATHNAME, "/proc/%d", pid) < 0) 
-               return 0;
-       if (stat(pathname, &st) != 0)
-               return 0;
-       return st.st_uid;
-}
-
-void add_mount_device(struct mountdev_list **mount_head,const char *fsname, const char *dir, dev_t device)
-{
-       struct mountdev_list *newmount;
-       /*printf("Adding mount Path: %s Dir:%s dev:%0x\n",dir, fsname, device);*/
-
-       if ( (newmount = malloc(sizeof(struct mountdev_list))) == NULL)
-               return;
-       newmount->fsname = strdup(fsname);
-       newmount->dir = strdup(dir);
-       newmount->device = device;
-       newmount->next = *mount_head;
-       *mount_head = newmount;
-}
-
-/*
- * scan_mount_devices : Create a list of mount points and devices
- *   This list is used later for matching purposes
- */
-void scan_mount_devices(const opt_type opts, struct mountdev_list **mount_devices)
-{
-       FILE *mntfp;
-       struct mntent *mnt_ptr;
-       struct stat st;
-       
-       if ( (mntfp = setmntent("/etc/mtab","r")) == NULL) {
-               fprintf(stderr, "Cannot open /etc/mtab: %s\n",
-                               strerror(errno));
-               return;
-       }
-       while ( (mnt_ptr = getmntent(mntfp)) != NULL) {
-               if (stat(mnt_ptr->mnt_dir, &st) == 0) {
-                       add_mount_device(mount_devices, mnt_ptr->mnt_fsname, mnt_ptr->mnt_dir, st.st_dev);
-               }
-       }
-}
-
-static dev_t get_netdev(void)
-{
-       int skt;
-       struct stat st;
-
-       if ( (skt = socket(PF_INET,SOCK_DGRAM,0)) < 0)
-               return -1;
-       if ( fstat(skt, &st) != 0) 
-               return -1;
-       return st.st_dev;
-}
-
-static void debug_match_lists(struct names *names_head, struct inode_list *ino_head, struct device_list *dev_head)
-{
-       struct names *nptr;
-       struct inode_list *iptr;
-       struct device_list *dptr;
-
-       fprintf(stderr,"Names:\n");
-       for (nptr=names_head; nptr!= NULL; nptr=nptr->next) 
-       {
-               fprintf(stderr, "\t%s %c\n", nptr->filename, nptr->name_space);
-       }
-       fprintf(stderr,"\nInodes:\n");
-       for (iptr=ino_head; iptr!=NULL; iptr=iptr->next)
-       {
-               fprintf(stderr, "\tDev:%0lx Inode:%0lx\n",
-                               (unsigned long)iptr->device, (unsigned long)iptr->inode);
-       }
-       fprintf(stderr,"\nDevices:\n");
-       for (dptr=dev_head; dptr!=NULL; dptr=dptr->next)
-       {
-               fprintf(stderr, "\tDev:%0lx\n",
-                               (unsigned long)dptr->device);
-       }
-}
-
-/* 0 = no, 1=yes */
-static int ask(const pid_t pid)
-{
-       int c, res;
-       size_t len = 0;
-       char *line = NULL;
-
-       fflush(stdout);
-       while(1) {
-               fprintf(stderr, _("Kill process %d ? (y/N) "), pid);
-               fflush(stderr);
-               if (getline(&line, &len, stdin) < 0)
-                       return 0;
-               if (line[0] == '\n') {
-                       free(line);
-                       return 0;
-               }
-               res = rpmatch(line);
-               if (res >= 0) {
-                       free(line);
-                       return res;
-               }
-       } /* while */
-}
-
-static void kill_matched_proc(struct procs *proc_head, const opt_type opts)
-{
-       struct procs *pptr;
-
-       for (pptr = proc_head ; pptr != NULL ; pptr = pptr->next ) {
-               if ( (opts & OPT_INTERACTIVE) && (ask(pptr->pid) == 0))
-                       continue;
-               fprintf(stderr, "debug killing proc %d\n", pptr->pid);
-       }
-}
diff --git a/src/oldfuser.c b/src/oldfuser.c
new file mode 100644 (file)
index 0000000..acf07d9
--- /dev/null
@@ -0,0 +1,1229 @@
+/*
+ * fuser.c - identify processes using files
+ *
+ * Copyright (C) 1993-2002 Werner Almesberger
+ * Copyright (C) 2002-2005 Craig Small
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <signal.h>
+#include <limits.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef __linux__
+#include <linux/kdev_t.h>      /* for MKDEV */
+#include <linux/major.h>       /* for LOOP_MAJOR */
+#endif
+#include <errno.h>
+
+#include "i18n.h"
+#include "comm.h"
+#include "loop.h"         /* for loop_info */
+#include "signals.h"
+
+
+#define PROC_BASE  "/proc"
+#define UID_UNKNOWN -1
+#define NAME_FIELD 20          /* space reserved for file name */
+
+#define MAX_LINE 256           /* longest line we may ever find in /proc */
+
+
+#ifndef LOOP_MAJOR             /* don't count on the headers too much ... */
+#define LOOP_MAJOR 7
+#endif
+
+#ifndef MAJOR
+#define MAJOR(arg) 6           /* something that doesn't = LOOP_MAJOR */
+#endif
+
+#ifndef MKDEV
+#define MKDEV(arg1, arg2) mknod("/dev/Isuck", arg1, arg2) /* this is wrong */
+#endif
+
+
+#define REF_FILE   1           /* an open file */
+#define REF_ROOT   2           /* current root */
+#define REF_CWD    4           /* current directory */
+#define REF_EXE    8           /* executable */
+#define REF_MMAP  16           /* mmap'ed file or library */
+
+#define FLAG_KILL  1           /* kill process */
+#define FLAG_UID   2           /* show uid */
+#define FLAG_VERB  4           /* show verbose output */
+#define FLAG_DEV   8           /* show all processes using this device */
+#define FLAG_ASK  16           /* ask before killing a process */
+
+
+typedef struct _net_cache
+{
+  struct sockaddr_storage rmt_addr;
+  int lcl_port;
+  int rmt_port;
+  ino_t ino;
+  struct _net_cache *next;
+}
+NET_CACHE;
+
+typedef struct _unix_cache
+{
+  dev_t fs_dev;
+  ino_t fs_ino;
+  ino_t net_ino;
+  struct _unix_cache *next;
+}
+UNIX_CACHE;
+
+typedef struct
+{
+  const char *name;
+  NET_CACHE *cache;
+  int once;
+}
+SPACE_DSC;
+
+typedef enum
+{ it_proc, it_mount, it_loop, it_swap }
+ITEM_TYPE;
+
+typedef struct item_dsc
+{
+  ITEM_TYPE type;
+  union
+  {
+    struct
+    {
+      pid_t pid;
+      int uid;                 /* must also accept UID_UNKNOWN */
+      int ref_set;
+    }
+    proc;
+    struct
+    {
+      const char *path;
+    }
+    misc;
+  }
+  u;
+  struct item_dsc *next;
+}
+ITEM_DSC;
+
+typedef struct file_dsc
+{
+  const char *name;            /* NULL if previous entry has name */
+  dev_t dev;
+  ino_t ino;
+  int flags, sig_num;
+  SPACE_DSC *name_space;       /* or NULL if no indication */
+  ITEM_DSC *items;
+  struct file_dsc *named, *next;
+}
+FILE_DSC;
+
+static SPACE_DSC name_spaces[] = {
+  {"file", NULL, 0},           /* must be first */
+  {"tcp", NULL, 0},
+  {"udp", NULL, 0},
+  {NULL, NULL, 0}
+};
+
+
+static FILE_DSC *files = NULL;
+static FILE_DSC *last_named = NULL;
+static UNIX_CACHE *unix_cache = NULL;
+static pid_t self;
+static int all = 0, found_item = 0;
+static dev_t net_dev;
+static int ipv4only = 0, ipv6only = 0;
+
+
+static void
+parse_net_file (SPACE_DSC * dsc,char *filename, NET_CACHE **lastptr,int version )
+{
+  FILE *file;
+  NET_CACHE *new, *last;
+  char line[MAX_LINE + 1];
+  char rmt_addr[128];
+  char addr6[128];
+  unsigned long tmp_ino;
+
+  if (!(file = fopen (filename, "r")))
+    {
+      perror (filename);
+      exit (1);
+    }
+  last = *lastptr;
+  (void) fgets (line, MAX_LINE, file);
+  while (fgets (line, MAX_LINE, file))
+    {
+      new = malloc (sizeof (NET_CACHE));
+      if (!new)
+       {
+         perror ("malloc");
+         exit (1);
+       }
+    if (sscanf (line, 
+        "%*d: %*x:%x %64[0-9A-Fa-f]:%x %*x %*x:%*x %*x:%*x %*x %*d %*d %lu",
+        &new->lcl_port, rmt_addr, &new->rmt_port, &tmp_ino) != 4)
+       {
+         free (new);
+         continue;
+       }
+      new->ino = tmp_ino;
+      if (strlen(rmt_addr) > 8) {
+        sscanf(rmt_addr, "%08X%08X%08X%08X",
+            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[0],
+            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[1],
+            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[2],
+            &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr.s6_addr32[3]);
+        inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&new->rmt_addr)->sin6_addr, addr6, sizeof(addr6));
+      } else {
+        sscanf(rmt_addr, "%X",
+            &((struct sockaddr_in *) &new->rmt_addr)->sin_addr.s_addr);
+            ((struct sockaddr *) &new->rmt_addr)->sa_family = AF_INET;
+      }
+      if (!new->ino)
+       {
+         free (new);
+         continue;
+       }
+      new->next = NULL;
+      if (last)
+       last->next = new;
+      else
+       dsc->cache = new;
+      last = new;
+    }
+  (void) fclose (file);
+  *lastptr = last;
+
+}
+
+static void
+fill_net_cache (SPACE_DSC * dsc)
+{
+  NET_CACHE *last;
+  struct stat statbuf;
+  char *buffer = malloc (strlen (PROC_BASE) + strlen (dsc->name) + 8);
+  if (!buffer)
+    return;
+
+  if (dsc->once)
+    return;
+  dsc->once = 1;
+  last = NULL;
+
+  /* Check to see if we have both namespace files, if we don't then silently
+   * not use them if not flags are specified and complain if the flags
+   * were specified.
+   */
+  
+  if (!ipv6only) {
+    sprintf (buffer, PROC_BASE "/net/%s", dsc->name);
+    if (stat(buffer, &statbuf) != 0) {
+      if (ipv4only) 
+        fprintf(stderr, _("-4 flag used but proc file %s is not readable\n"), buffer);
+    } else {
+      parse_net_file (dsc, buffer, &last,4 );
+    }
+  }
+  if (!ipv4only) {
+    sprintf (buffer, PROC_BASE "/net/%s6", dsc->name);
+    if (stat(buffer, &statbuf) != 0) {
+      if (ipv6only) 
+        fprintf(stderr, _("-6 flag used but proc file %s is not readable\n"), buffer);
+    } else {
+      parse_net_file (dsc, buffer, &last,6 );
+    }
+  }
+}
+
+
+static void
+fill_unix_cache (void)
+{
+  static int once;
+  FILE *file;
+  UNIX_CACHE *new, *last;
+  struct stat st;
+  char *path = NULL, line[MAX_LINE + 1];
+  int ino;
+
+  if (once)
+    return;
+  once = 1;
+  if (!(file = fopen (PROC_BASE "/net/unix", "r")))
+    {
+      perror (PROC_BASE "/net/unix");
+      exit (1);
+    }
+  last = NULL;
+  (void) fgets (line, MAX_LINE, file);
+  while (fgets (line, MAX_LINE, file))
+    {
+      if (sscanf (line, "%*x: %*x %*x %*x %*x %*x %d %as", &ino, &path) != 2)
+       continue;
+      if (stat (path, &st) < 0) {
+       free (path);
+       continue;
+      }
+      free (path);
+
+      new = malloc (sizeof (UNIX_CACHE));
+      new->fs_dev = st.st_dev;
+      new->fs_ino = st.st_ino;
+      new->net_ino = ino;
+      new->next = NULL;
+      if (last)
+       last->next = new;
+      else
+       unix_cache = new;
+      last = new;
+    }
+  (void) fclose (file);
+
+}
+
+
+static unsigned long
+try_to_find_unix_dev (ino_t inode)
+{
+  UNIX_CACHE *walk;
+
+  for (walk = unix_cache; walk; walk = walk->next)
+    if (walk->net_ino == inode)
+      return walk->fs_dev;
+  return 0;
+}
+
+
+static void
+add_file (const char *path, dev_t device, ino_t inode,
+         pid_t pid, int ref)
+{
+  struct stat st;
+  FILE_DSC *file, *next;
+  ITEM_DSC **item, *this;
+  dev_t mount_dev;
+
+  if (device)
+    mount_dev = device;
+  else
+    mount_dev = try_to_find_unix_dev (inode);
+  for (file = files; file; file = next)
+    {
+      next = file->next;
+      if (file->flags & FLAG_DEV ? mount_dev && mount_dev == file->dev :
+         device == file->dev && inode == file->ino)
+       {
+         if (!file->name)
+           file = file->named;
+         for (item = &file->items; *item; item = &(*item)->next)
+           if ((*item)->type == it_proc && (*item)->u.proc.pid >= pid)
+             break;
+         if (*item && (*item)->u.proc.pid == pid)
+           this = *item;
+         else
+           {
+             if (!(this = malloc (sizeof (ITEM_DSC))))
+               {
+                 perror ("malloc");
+                 exit (1);
+               }
+             this->type = it_proc;
+             this->u.proc.pid = pid;
+             this->u.proc.uid = UID_UNKNOWN;
+             this->u.proc.ref_set = 0;
+             this->next = *item;
+             *item = this;
+             found_item = 1;
+           }
+         this->u.proc.ref_set |= ref;
+         if ((file->flags & (FLAG_UID | FLAG_VERB)) && this->u.proc.uid ==
+             UID_UNKNOWN && lstat (path, &st) >= 0)
+           this->u.proc.uid = st.st_uid;
+       }
+    }
+}
+
+
+static void
+add_other (ITEM_TYPE type, dev_t mount_dev,
+          dev_t device, ino_t inode, const char *path)
+{
+  FILE_DSC *file, *next;
+  ITEM_DSC **item, *this;
+
+  for (file = files; file; file = next)
+    {
+      next = file->next;
+      if (file->flags & FLAG_DEV ? mount_dev == file->dev :
+         device == file->dev && inode == file->ino)
+       {
+         if (!file->name)
+           file = file->named;
+         for (item = &file->items; *item; item = &(*item)->next);
+         /* there's no easy way to suppress duplicates, so we don't */
+         if (!(this = malloc (sizeof (ITEM_DSC))))
+           {
+             perror ("malloc");
+             exit (1);
+           }
+         this->type = type;
+         if (!(this->u.misc.path = strdup (path)))
+           {
+             perror ("strdup");
+             exit (1);
+           }
+         this->next = *item;
+         *item = this;
+         found_item = 1;
+       }
+    }
+}
+
+
+static void
+check_link (const char *path, pid_t pid, int type)
+{
+  struct stat st;
+
+  if (stat (path, &st) >= 0)
+    add_file (path, st.st_dev, st.st_ino, pid, type);
+}
+
+
+static void
+check_map (const char *rel, pid_t pid, int type)
+{
+  FILE *file;
+  char line[MAX_LINE + 1];
+  int major, minor;
+  ino_t inode;
+  unsigned long long tmp_inode;
+
+  if (!(file = fopen (rel, "r")))
+    return;
+  while (fgets (line, MAX_LINE, file))
+    {
+      if (sscanf (line, "%*s %*s %*s %x:%x %lld", &major, &minor, &tmp_inode) != 3)
+       continue;
+      if (major || minor || tmp_inode) {
+        inode = (ino_t)(tmp_inode);
+           add_file (rel, MKDEV (major, minor), inode, pid, type);
+      }
+    }
+  fclose (file);
+}
+
+
+static void
+check_dir (const char *rel, pid_t pid, int type)
+{
+  DIR *dir;
+  struct dirent *de;
+  char *path;
+
+  if (!(dir = opendir (rel)))
+    return;
+  while ((de = readdir (dir)) != NULL)
+    if (strcmp (de->d_name, ".") && strcmp (de->d_name, ".."))
+      {
+       asprintf (&path, "%s/%s", rel, de->d_name);
+       check_link (path, pid, type);
+       free (path);
+      }
+  (void) closedir (dir);
+}
+
+
+static void
+scan_fd (void)
+{
+  DIR *dir;
+  struct dirent *de;
+  char *path;
+  pid_t pid;
+  int empty;
+
+  if (!(dir = opendir (PROC_BASE)))
+    {
+      perror (PROC_BASE);
+      exit (1);
+    }
+  empty = 1;
+  while ((de = readdir (dir)) != NULL)
+    if ((pid = (pid_t)atoi (de->d_name)) != 0)
+      {
+       empty = 0;
+       if (asprintf (&path, "%s/%d", PROC_BASE, pid) < 0)
+         continue;
+       if (chdir (path) >= 0)
+         {
+           check_link ("root", pid, REF_ROOT);
+           check_link ("cwd", pid, REF_CWD);
+           check_link ("exe", pid, REF_EXE);
+           check_dir ("lib", pid, REF_MMAP);
+           check_dir ("mmap", pid, REF_MMAP);
+           check_map ("maps", pid, REF_MMAP);
+           check_dir ("fd", pid, REF_FILE);
+         }
+       free (path);
+      }
+  (void) closedir (dir);
+  if (empty)
+    {
+      fprintf (stderr, _("%s is empty (not mounted ?)\n"),PROC_BASE);
+      exit (1);
+    }
+}
+
+
+static void
+scan_mounts (void)
+{
+  FILE *file;
+  struct stat st_dev, st_parent, st_mounted;
+  char line[MAX_LINE + 1], *path = NULL, *mounted = NULL;
+  char *end;
+
+  if (!(file = fopen (PROC_BASE "/mounts", "r")))
+    return;                    /* old kernel */
+  while (fgets (line, MAX_LINE, file))
+    {
+      if (sscanf (line, "%as %as", &path, &mounted) != 2)
+       continue;
+      if ( stat (path, &st_dev) == 0) {
+       if (S_ISBLK (st_dev.st_mode) && MAJOR (st_dev.st_rdev) == LOOP_MAJOR) {
+               struct loop_info loopinfo;
+               int fd;
+
+               if ((fd = open(path, O_RDWR)) > 0) {
+                       if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) >= 0) {
+                               add_other(it_loop,loopinfo.lo_device,loopinfo.lo_device,loopinfo.lo_inode,path);
+                       }
+                       (void) close(fd);
+                }
+       }
+      }
+      if (stat (mounted, &st_mounted) < 0)
+       {
+         free (path);
+         free (mounted);
+         continue;
+       }
+      if (asprintf (&end, "%s/..", mounted) < 0)
+       {
+         free (path);
+         free (mounted);
+         continue;
+       }
+
+      if (stat (end, &st_parent) >= 0)
+       {
+         add_other (it_mount, st_parent.st_dev, st_mounted.st_dev,
+                    st_mounted.st_ino, mounted);
+       }
+      free (end);
+      free (path);
+      free (mounted);
+    }
+  (void) fclose (file);
+}
+
+
+static void
+scan_swaps (void)
+{
+  FILE *file;
+  struct stat st;
+  char line[MAX_LINE + 1], *path, type[MAX_LINE + 1];
+
+  if (!(file = fopen (PROC_BASE "/swaps", "r")))
+    return;                    /* old kernel */
+  (void) fgets (line, MAX_LINE, file);
+  while (fgets (line, MAX_LINE, file))
+    {
+      if (sscanf (line, "%as %s", &path, type) != 2)
+       continue;               /* new kernel :-) */
+      if (strcmp (type, "file")) {
+       free (path);
+       continue;
+      }
+      if (stat (path, &st) >= 0)
+       add_other (it_swap, st.st_dev, st.st_dev, st.st_ino, path);
+      free (path);
+    }
+  (void) fclose (file);
+}
+
+
+static int
+ask (pid_t pid)
+{
+  int res;
+  size_t len;
+  char *line;
+
+  line = NULL;
+  len = 0;
+
+  fflush (stdout);
+  do {
+    fprintf (stderr, _("Kill process %d ? (y/N) "), pid);
+    fflush (stderr);
+
+    if (getline (&line, &len, stdin) < 0)
+      return 0;
+    /* Check for default */
+    if (line[0] == '\n') {
+      free(line);
+      return 0;
+    }
+    res = rpmatch(line);
+    if (res >= 0) {
+      free(line);
+      return res;
+    }
+  } while(1);
+  /* Never should get here */
+  return 0;
+}
+
+static void
+kill_item (const FILE_DSC * file, const ITEM_DSC * item)
+{
+  char tmp[10];
+
+  switch (item->type)
+    {
+    case it_proc:
+      if (item->u.proc.pid == self)
+       return;
+      if ((file->flags & FLAG_ASK) && !ask (item->u.proc.pid))
+       return;
+      if (kill (item->u.proc.pid, file->sig_num) >= 0)
+       break;
+      sprintf (tmp, _("kill %d"), item->u.proc.pid);
+      perror (tmp);
+      break;
+    case it_mount:
+      fprintf (stderr, _("No automatic removal. Please use  umount %s\n"),
+              item->u.misc.path);
+      break;
+    case it_loop:
+      fprintf (stderr, _("No automatic removal. Please use  umount %s\n"),
+              item->u.misc.path);
+      break;
+    case it_swap:
+      fprintf (stderr, _("No automatic removal. Please use  swapoff %s\n"),
+              file->name);
+      break;
+    }
+}
+
+
+static void
+show_files_or_kill (void)
+{
+  const FILE_DSC *file;
+  const ITEM_DSC *item;
+  FILE *f;
+  const struct passwd *pw;
+  const char *user, *scan;
+  char tmp[10], *path, comm[COMM_LEN + 1];
+  int length, header, first, dummy, last_namelen = 0;
+  header = 1;
+  for (file = files; file; file = file->next)
+    if (file->name && (file->items || all))
+      {
+       if (header && (file->flags & FLAG_VERB))
+         {
+           fprintf (stderr, _("\n%*s USER        PID ACCESS COMMAND\n"),
+                    NAME_FIELD, "");
+           header = 0;
+         }
+       length = 0;
+       for (scan = file->name; scan && *scan; scan++)
+         if (*scan == '\\')
+           length += fprintf (stderr, "\\\\");
+         else if (*scan > ' ' && *scan <= '~')
+           {
+             putc(*scan,stderr);
+             length++;
+           }
+         else
+           length += fprintf (stderr, "\\%03o", *scan);
+       if (file->name_space)
+         length += fprintf (stderr, "/%s", file->name_space->name);
+
+       if (length > 0)
+         last_namelen=length;
+       else
+         fprintf(stderr, "\n%*.*s",last_namelen,last_namelen," ");
+
+       if (!(file->flags & FLAG_VERB))
+         {
+           putc (':',stderr);
+           length++;
+         }
+
+       first = 1;
+       for (item = file->items; item; item = item->next)
+         {
+           if (!(file->flags & FLAG_VERB))
+             {
+               if (item->type != it_proc)
+                 continue;
+        if ((first==1) && (item->u.proc.ref_set & (REF_FILE|REF_ROOT|REF_CWD|REF_EXE|REF_MMAP))) {
+    while (length < NAME_FIELD)
+    {
+      putc(' ',stderr);
+      length++;
+    }
+        }
+               printf ("%6d", item->u.proc.pid);
+        fflush(stdout);
+               /* if (item->u.proc.ref_set & REF_FILE)*/
+               if (item->u.proc.ref_set & REF_ROOT)
+                 putc ('r', stderr);
+               if (item->u.proc.ref_set & REF_CWD)
+                 putc ('c', stderr);
+               if (item->u.proc.ref_set & REF_EXE)
+                 putc ('e', stderr);
+               else if (item->u.proc.ref_set & REF_MMAP)
+                 putc ('m', stderr);
+               if ((file->flags & FLAG_UID) && item->u.proc.uid !=
+                   UID_UNKNOWN)
+                {
+                 if ((pw = getpwuid (item->u.proc.uid)) != NULL) {
+                   fprintf (stderr, "(%s)", pw->pw_name);
+                  } else {
+                   fprintf (stderr, "(%d)", item->u.proc.uid);
+                  }
+                }
+               first = 0;
+             }
+           else
+             {
+               const char *name;
+               int uid;
+
+               switch (item->type)
+                 {
+                 case it_proc:
+                   asprintf (&path, PROC_BASE "/%d/stat", item->u.proc.pid);
+                   strcpy (comm, "???");
+                   if ((f = fopen (path, "r")) != NULL)
+                     {
+                       (void) fscanf (f, "%d (%[^)]", &dummy, comm);
+                       (void) fclose (f);
+                     }
+                   free (path);
+                   name = comm;
+                   uid = item->u.proc.uid;
+                   break;
+                 case it_mount:
+                 case it_loop:
+                 case it_swap:
+                   name = item->u.misc.path;
+                   uid = 0;
+                   break;
+                 default:
+                   fprintf (stderr, _("Internal error (type %d)\n"),
+                            item->type);
+                   exit (1);
+                 }
+               if (uid == UID_UNKNOWN)
+                 user = "???";
+               else if ((pw = getpwuid (uid)) != NULL)
+                 user = pw->pw_name;
+               else
+                 {
+                   sprintf (tmp, "%d", uid);
+                   user = tmp;
+                 }
+               if (!first)
+                 fprintf (stderr, "%*s", NAME_FIELD, "");
+               else if (length > NAME_FIELD)
+                 fprintf (stderr, "\n%*s", NAME_FIELD, "");
+        else
+          while (length < NAME_FIELD)
+          {
+            putc(' ', stderr);
+            length++;
+          }
+               fprintf (stderr, " %-8s ", user);
+               switch (item->type)
+                 {
+                 case it_proc:
+                   printf ("%6d", item->u.proc.pid);
+            fflush(stdout);
+            fprintf (stderr, " %c%c%c%c%c  ",
+                           item->u.proc.ref_set & REF_FILE ? 'f' : '.',
+                           item->u.proc.ref_set & REF_ROOT ? 'r' : '.',
+                           item->u.proc.ref_set & REF_CWD ? 'c' : '.',
+                           item->u.proc.ref_set & REF_EXE ? 'e' : '.',
+                           (item->u.proc.ref_set & REF_MMAP) &&
+                           !(item->u.proc.ref_set & REF_EXE) ? 'm' : '.');
+                   break;
+                 case it_mount:
+                   fprintf (stderr, _("kernel mount  "));
+                   break;
+                 case it_loop:
+                   fprintf (stderr, _("kernel loop   "));
+                   break;
+                 case it_swap:
+                   fprintf (stderr, _("kernel swap   "));
+                   break;
+                 }
+               if (name)
+                {
+                 for (scan = name; *scan; scan++)
+                   if (*scan == '\\')
+                     fprintf (stderr, "\\\\");
+                   else if (*scan > ' ' && *scan <= '~')
+                     putc (*scan,stderr);
+                   else
+                     fprintf (stderr, "\\%03o", (unsigned char) *scan);
+                }
+               putc ('\n',stderr);
+             }
+           first = 0;
+         }
+       if (!(file->flags & FLAG_VERB) || first)
+         putc('\n',stderr);
+       if (file->flags & FLAG_KILL)
+         for (item = file->items; item; item = item->next)
+           kill_item (file, item);
+      }
+}
+
+
+static void
+kill_files (void)
+{
+  const FILE_DSC *file;
+  const ITEM_DSC *item;
+
+  for (file = files; file; file = file->next)
+    if (file->flags & FLAG_KILL)
+      for (item = file->items; item; item = item->next)
+       kill_item (file, item);
+}
+
+
+static void
+enter_item (const char *name, int flags, int sig_number, dev_t dev,
+           ino_t ino, SPACE_DSC * name_space)
+{
+  static FILE_DSC *last = NULL;
+  FILE_DSC *new;
+
+  if (!(new = malloc (sizeof (FILE_DSC))))
+    {
+      perror ("malloc");
+      exit (1);
+    }
+  if (last_named && !strcmp (last_named->name, name) &&
+      last_named->name_space == name_space)
+    new->name = NULL;
+  else if (!(new->name = strdup (name)))
+    {
+      perror ("strdup");
+      exit (1);
+    }
+  new->flags = flags;
+  new->sig_num = sig_number;
+  new->items = NULL;
+  new->next = NULL;
+  new->dev = dev;
+  new->ino = ino;
+  new->name_space = name_space;
+  if (last)
+    last->next = new;
+  else
+    files = new;
+  last = new;
+  new->named = last_named;
+  if (new->name)
+    last_named = new;
+}
+
+
+static int
+parse_inet (const char *spec, const char *name_space, int *lcl_port,
+           struct sockaddr_storage *rmt_addr, int *rmt_port)
+{
+  char *s, *here, *next, *end;
+  int port, field, address_match;
+
+  if (!(s = strdup (spec)))
+    {
+      perror ("strdup");
+      exit (1);
+    }
+  *lcl_port = *rmt_port = -1;
+  memset(rmt_addr, 0, sizeof(struct sockaddr_storage));
+  field = 0;
+  address_match = 0;
+  for (here = s; here; here = next ? next + 1 : NULL)
+    {
+      next = strchr (here, ',');
+      if (next)
+       *next = 0;
+      switch (field)
+       {
+       case 0:
+         /* fall through */
+       case 2:
+         if (!*here)
+           break;
+         port = strtoul (here, &end, 0);
+         if (*end)
+           {
+             struct servent *se;
+
+             if (!(se = getservbyname (here, name_space)))
+               return 0;
+             port = ntohs (se->s_port);
+           }
+         if (field)
+           *rmt_port = port;
+         else
+           *lcl_port = port;
+         break;
+       case 1:
+         if (!*here)
+           break;
+          if (!ipv4only) {
+
+            if (inet_pton(AF_INET6, here, &((struct sockaddr_in6*)rmt_addr)->sin6_addr) > 0) {
+              address_match = 1;
+              rmt_addr->ss_family = AF_INET6;
+             }
+          }
+          if (!ipv6only && !address_match) {
+            if (inet_pton(AF_INET, here, &((struct sockaddr_in*)rmt_addr)->sin_addr) > 0) {
+              address_match = 1;
+              rmt_addr->ss_family = AF_INET6;
+            }
+          }
+            
+         break;
+       default:
+         return 0;
+       }
+      field++;
+    }
+  return 1;
+}
+
+static void find_net_dev(void)
+{
+  int fd = socket(PF_INET, SOCK_DGRAM,0);
+  struct stat buf;
+  if (fd >= 0 && fstat(fd, &buf) == 0) {
+    net_dev = buf.st_dev;
+    close(fd);
+    return;
+  }
+  if (fd >= 0)
+    close(fd);
+  fprintf(stderr,_("can't find sockets' device number"));
+}
+
+
+
+static void
+usage (void)
+{
+  fprintf (stderr, _(
+    "Usage: fuser [ -a | -s | -c ] [ -n SPACE ] [ -SIGNAL ] [ -kimuv ] NAME...\n"
+    "             [ - ] [ -n SPACE ] [ -SIGNAL ] [ -kimuv ] NAME...\n"
+    "       fuser -l\n"
+    "       fuser -V\n"
+    "Show which processes use the named files, sockets, or filesystems.\n\n "
+    "    -a        display unused files too\n"
+    "    -c        mounted FS\n"
+    "    -f        silently ignored (for POSIX compatibility)\n"
+    "    -i        ask before killing (ignored without -k)\n"
+    "    -k        kill processes accessing the named file\n"
+    "    -l        list available signal names\n"
+    "    -m        show all processes using the named filesystems\n"
+    "    -n SPACE  search in this name space (file, udp, or tcp)\n"
+    "    -s        silent operation\n"
+    "    -SIGNAL   send this signal instead of SIGKILL\n"
+    "    -u        display user IDs\n"
+    "    -v        verbose output\n"
+    "    -V        display version information\n"
+    "    -4        search IPv4 sockets only\n"
+    "    -6        search IPv6 sockets only\n"
+    "    -         reset options\n\n"
+    "  udp/tcp names: [local_port][,[rmt_host][,[rmt_port]]]\n\n"));
+  exit (1);
+}
+
+void print_version()
+{
+  fprintf(stderr, _("fuser (PSmisc) %s\n"), VERSION);
+  fprintf(stderr, _(
+    "Copyright (C) 1993-2005 Werner Almesberger and Craig Small\n\n"));
+  fprintf(stderr, _(
+    "PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
+    "This is free software, and you are welcome to redistribute it under\n"
+    "the terms of the GNU General Public License.\n"
+    "For more information about these matters, see the files named COPYING.\n"));
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  SPACE_DSC *name_space;
+  int flags, silent, do_kill, sig_number, no_files;
+
+  flags = silent = do_kill = 0;
+  sig_number = SIGKILL;
+  name_space = name_spaces;
+  no_files = 1;
+
+  /* Setup the i18n */
+#ifdef ENABLE_NLS
+  setlocale(LC_ALL, "");
+  bindtextdomain(PACKAGE, LOCALEDIR);
+  textdomain(PACKAGE);
+#endif
+
+  if (argc < 2)
+    usage ();
+  if (argc == 2 && !strcmp (argv[1], "-l"))
+    {
+      list_signals ();
+      return 0;
+    }
+  find_net_dev();
+  while (--argc)
+    {
+      argv++;
+      if (**argv == '-')
+       if (!argv[0][1])
+         {
+           flags = 0;
+           sig_number = SIGKILL;
+         }
+       else
+         while (*++*argv)
+           {
+             int end;
+
+             end = 0;
+             switch (**argv)
+               {
+               case 'a':
+                 all = 1;
+                 break;
+        case 'f':
+          break;
+               case 'k':
+                 flags |= FLAG_KILL;
+                 do_kill = 1;
+                 break;
+               case 'i':
+                 flags |= FLAG_ASK;
+                 break;
+               case 'm':
+               case 'c':
+                 flags |= FLAG_DEV;
+                 break;
+               case 'n':
+                 if (!--argc)
+                   usage ();
+                 argv++;
+                 for (name_space = name_spaces; name_space->name;
+                      name_space++)
+                   if (!strcmp (*argv, name_space->name))
+                     break;
+                 if (!name_space->name)
+                   usage ();
+                 end = 1;
+                 break;
+               case 's':
+                 silent = 1;
+                 break;
+               case 'u':
+                 flags |= FLAG_UID;
+                 break;
+               case 'v':
+                 flags |= FLAG_VERB;
+                 break;
+               case 'V':
+                 print_version();
+                 return 0;
+                case '4':
+                    if (ipv6only) 
+                      usage();
+                    ipv4only = 1;
+                    break;
+                case '6':
+                    if (ipv4only)
+                      usage();
+                    ipv6only = 1;
+                    break;
+               default:
+                 if (isupper (**argv) || isdigit (**argv))
+                   {
+                     sig_number = get_signal (*argv, "fuser");
+                     argv[0][1] = 0;
+                     break;
+                   }
+                 usage ();
+               }
+             if (end)
+               break;
+           }
+      else
+       {
+         SPACE_DSC *this_name_space;
+         struct stat st;
+         char *here;
+
+         no_files = 0;
+         last_named = NULL;
+         this_name_space = name_space;
+         if (name_space != name_spaces || stat (*argv, &st) < 0)
+           {
+             here = strchr (*argv, '/');
+             if (here && here != *argv)
+               {
+                 for (this_name_space = name_spaces; this_name_space->name;
+                      this_name_space++)
+                   if (!strcmp (here + 1, this_name_space->name))
+                     {
+                       *here = 0;
+                       break;
+                     }
+                 if (!this_name_space->name)
+                   this_name_space = name_spaces;
+               }
+           }
+         if (this_name_space == name_spaces)
+           {
+             if (stat (*argv, &st) < 0)
+               {
+                 perror (*argv);
+                 continue;
+               }
+             if (flags & FLAG_DEV)
+              {
+               if (S_ISBLK (st.st_mode))
+                 st.st_dev = st.st_rdev;
+               else if (S_ISDIR (st.st_mode))
+                 {
+                   if (stat (*argv, &st) < 0)
+                     {
+                       perror (*argv);
+                       continue;
+                     }
+                 }
+              }
+             if (S_ISSOCK (st.st_mode) || (flags & FLAG_DEV))
+               fill_unix_cache ();
+             if (!S_ISSOCK (st.st_mode) || (flags & FLAG_DEV))
+               enter_item (*argv, flags, sig_number, st.st_dev, st.st_ino,
+                           NULL);
+             else
+               {
+                 UNIX_CACHE *walk;
+
+                 for (walk = unix_cache; walk; walk = walk->next)
+                   if (walk->fs_dev == st.st_dev && walk->fs_ino ==
+                       st.st_ino)
+                     enter_item (*argv, flags, sig_number, net_dev,
+                        walk->net_ino, NULL);
+               }
+           }
+         else
+           {
+             NET_CACHE *walk;
+             struct sockaddr_storage rmt_addr;
+             int lcl_port, rmt_port;
+
+             if (flags & FLAG_DEV)
+               {
+                 fprintf (stderr, _("ignoring -m in name space \"%s\"\n"),
+                          this_name_space->name);
+                 flags &= ~FLAG_DEV;
+               }
+             fill_net_cache (this_name_space);
+             if (!parse_inet (*argv, this_name_space->name, &lcl_port,
+                              &rmt_addr, &rmt_port))
+               {
+                 fprintf (stderr, _("%s/%s: invalid specification\n"), *argv,
+                          this_name_space->name);
+                 continue;
+               }
+             for (walk = this_name_space->cache; walk; walk = walk->next)
+               if ((lcl_port == -1 || walk->lcl_port == lcl_port) &&
+                   (rmt_addr.ss_family == 0 || ( memcmp(
+                     &((struct sockaddr_in6*)&walk->rmt_addr)->sin6_addr,
+                     &((struct sockaddr_in6*)&rmt_addr)->sin6_addr,
+                     sizeof(struct in6_addr)) == 0) ) &&
+                   (rmt_port == -1 || walk->rmt_port == rmt_port))
+                 enter_item (*argv, flags, sig_number, net_dev, walk->ino,
+                             this_name_space);
+           }
+       }
+    }
+  if (no_files || (all && silent))
+    usage ();
+  scan_fd ();
+  scan_mounts ();
+  scan_swaps ();
+  if (do_kill && seteuid (getuid ()) < 0)
+    {
+      perror ("seteuid");
+      return 1;
+    }
+  self = getpid ();
+  if (silent)
+    kill_files ();
+  else
+    show_files_or_kill ();
+  return found_item ? 0 : 1;
+}