]> granicus.if.org Git - procps-ng/commitdiff
pmap: new usage & fix coding style
authorSami Kerola <kerolasa@iki.fi>
Sun, 5 Jun 2011 16:05:26 +0000 (18:05 +0200)
committerSami Kerola <kerolasa@iki.fi>
Tue, 20 Dec 2011 16:17:01 +0000 (17:17 +0100)
Coding style fixed and more readable help output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
pmap.c

diff --git a/pmap.c b/pmap.c
index c92737d882d75c72cc8503e341e5485aae6202f5..a61dd2e13e69e1a9afb0b2ffcb7838b84c064e5a 100644 (file)
--- a/pmap.c
+++ b/pmap.c
  * GNU Library General Public License for more details.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-
 #include <sys/ipc.h>
 #include <sys/shm.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
+#include "proc/escape.h"
 #include "proc/readproc.h"
 #include "proc/version.h"
-#include "proc/escape.h"
 
-static void usage(void) NORETURN;
-static void usage(void){
-  fprintf(stderr,
-    "Usage: pmap [-x | -d] [-q] [-A low,high] pid...\n"
-    "-x  show details\n"
-    "-d  show offset and device number\n"
-    "-q  quiet; less header/footer info\n"
-    "-V  show the version number\n"
-    "-A  limit results to the given range\n"
-  );
-  exit(1);
+static void __attribute__ ((__noreturn__))
+    usage(FILE * out)
+{
+       fprintf(out,
+               "\nUsage: %s [options] pid [pid ...]\n"
+               "\nOptions:\n", program_invocation_short_name);
+       fprintf(out,
+               "  -x, --extended              show details\n"
+               "  -d, --device                show the device format\n"
+               "  -q, --quiet                 do not display header and footer\n"
+               "  -A, --range=<low>[,<high>]  limit results to the given range\n"
+               "  -h, --help                  display this help text\n"
+               "  -V, --version               display version information and exit\n");
+       fprintf(out, "\nFor more information see pmap(1).\n");
+       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 }
 
-
 static unsigned KLONG range_low;
 static unsigned KLONG range_high = ~0ull;
 
-static int V_option;
-static int r_option;  // ignored -- for SunOS compatibility
-static int x_option;
 static int d_option;
 static int q_option;
+static int x_option;
 
 static unsigned shm_minor = ~0u;
 
-static void discover_shm_minor(void){
-  void *addr;
-  int shmid;
-  char mapbuf[256];
-
-  if(!freopen("/proc/self/maps", "r", stdin)) return;
-
-  // create
-  shmid = shmget(IPC_PRIVATE, 42, IPC_CREAT | 0666);
-  if(shmid==-1) return; // failed; oh well
-  // attach
-  addr = shmat(shmid, NULL, SHM_RDONLY);
-  if(addr==(void*)-1) goto out_destroy;
-
-  while(fgets(mapbuf, sizeof mapbuf, stdin)){
-    char flags[32];
-    char *tmp; // to clean up unprintables
-    unsigned KLONG start, end;
-    unsigned long long file_offset, inode;
-    unsigned dev_major, dev_minor;
-    sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
-    tmp = strchr(mapbuf,'\n');
-    if(tmp) *tmp='\0';
-    tmp = mapbuf;
-    while(*tmp){
-      if(!isprint(*tmp)) *tmp='?';
-      tmp++;
-    }
-    if(start > (unsigned long)addr) continue;
-    if(dev_major) continue;
-    if(flags[3] != 's') continue;
-    if(strstr(mapbuf,"/SYSV")){
-      shm_minor = dev_minor;
-      break;
-    }
-  }
-
-  if(shmdt(addr)) perror("shmdt");
-
-out_destroy:
-  if(shmctl(shmid, IPC_RMID, NULL)) perror("IPC_RMID");
-
-  return;
+static void discover_shm_minor(void)
+{
+       void *addr;
+       int shmid;
+       char mapbuf[256];
+
+       if (!freopen("/proc/self/maps", "r", stdin))
+               return;
+
+       /* create */
+       shmid = shmget(IPC_PRIVATE, 42, IPC_CREAT | 0666);
+       if (shmid == -1)
+               /* failed; oh well */
+               return;
+       /* attach */
+       addr = shmat(shmid, NULL, SHM_RDONLY);
+       if (addr == (void *)-1)
+               goto out_destroy;
+
+       while (fgets(mapbuf, sizeof mapbuf, stdin)) {
+               char flags[32];
+               /* to clean up unprintables */
+               char *tmp;
+               unsigned KLONG start, end;
+               unsigned long long file_offset, inode;
+               unsigned dev_major, dev_minor;
+               sscanf(mapbuf, "%" KLF "x-%" KLF "x %31s %Lx %x:%x %Lu", &start,
+                      &end, flags, &file_offset, &dev_major, &dev_minor,
+                      &inode);
+               tmp = strchr(mapbuf, '\n');
+               if (tmp)
+                       *tmp = '\0';
+               tmp = mapbuf;
+               while (*tmp) {
+                       if (!isprint(*tmp))
+                               *tmp = '?';
+                       tmp++;
+               }
+               if (start > (unsigned long)addr)
+                       continue;
+               if (dev_major)
+                       continue;
+               if (flags[3] != 's')
+                       continue;
+               if (strstr(mapbuf, "/SYSV")) {
+                       shm_minor = dev_minor;
+                       break;
+               }
+       }
+
+       if (shmdt(addr))
+               perror("shmdt");
+
+ out_destroy:
+       if (shmctl(shmid, IPC_RMID, NULL))
+               perror("IPC_RMID");
+
+       return;
 }
 
-
-static const char *mapping_name(proc_t *p, unsigned KLONG addr, unsigned KLONG len, const char *mapbuf, unsigned showpath, unsigned dev_major, unsigned dev_minor, unsigned long long inode){
-  const char *cp;
-
-  if(!dev_major && dev_minor==shm_minor && strstr(mapbuf,"/SYSV")){
-    static char shmbuf[64];
-    snprintf(shmbuf, sizeof shmbuf, "  [ shmid=0x%Lx ]", inode);
-    return shmbuf;
-  }
-
-  cp = strrchr(mapbuf,'/');
-  if(cp){
-    if(showpath) return strchr(mapbuf,'/');
-    return cp[1] ? cp+1 : cp;
-  }
-
-  cp = strchr(mapbuf,'/');
-  if(cp){
-    if(showpath) return cp;
-    return strrchr(cp,'/') + 1;  // it WILL succeed
-  }
-
-  cp = "  [ anon ]";
-  if( (p->start_stack >= addr) && (p->start_stack <= addr+len) )  cp = "  [ stack ]";
-  return cp;
+static const char *mapping_name(proc_t * p, unsigned KLONG addr,
+                               unsigned KLONG len, const char *mapbuf,
+                               unsigned showpath, unsigned dev_major,
+                               unsigned dev_minor, unsigned long long inode)
+{
+       const char *cp;
+
+       if (!dev_major && dev_minor == shm_minor && strstr(mapbuf, "/SYSV")) {
+               static char shmbuf[64];
+               snprintf(shmbuf, sizeof shmbuf, "  [ shmid=0x%Lx ]", inode);
+               return shmbuf;
+       }
+
+       cp = strrchr(mapbuf, '/');
+       if (cp) {
+               if (showpath)
+                       return strchr(mapbuf, '/');
+               return cp[1] ? cp + 1 : cp;
+       }
+
+       cp = strchr(mapbuf, '/');
+       if (cp) {
+               if (showpath)
+                       return cp;
+               /* it WILL succeed */
+               return strrchr(cp, '/') + 1;
+       }
+
+       cp = "  [ anon ]";
+       if ((p->start_stack >= addr) && (p->start_stack <= addr + len))
+               cp = "  [ stack ]";
+       return cp;
 }
 
-static int one_proc(proc_t *p){
-  char buf[32];
-  char mapbuf[9600];
-  char cmdbuf[512];
-  FILE *fp;
-  unsigned long total_shared = 0ul;
-  unsigned long total_private_readonly = 0ul;
-  unsigned long total_private_writeable = 0ul;
-
-  char *cp2=NULL;
-  unsigned long long rss = 0ull;
-  unsigned long long private_dirty = 0ull;
-  unsigned long long shared_dirty = 0ull;
-  unsigned long long total_rss = 0ull;
-  unsigned long long total_private_dirty = 0ull;
-  unsigned long long total_shared_dirty = 0ull;
-
-  // Overkill, but who knows what is proper? The "w" prog
-  // uses the tty width to determine this.
-  int maxcmd = 0xfffff;
-
-  sprintf(buf,"/proc/%u/maps",p->tgid);
-  if ( (fp = fopen(buf, "r")) == NULL) return 1;
-  if (x_option) {
-    sprintf(buf,"/proc/%u/smaps",p->tgid);
-    if ( (fp = freopen(buf, "r", fp)) == NULL) return 1;
-  }
-
-  escape_command(cmdbuf, p, sizeof cmdbuf, &maxcmd, ESC_ARGS|ESC_BRACKETS);
-  printf("%u:   %s\n", p->tgid, cmdbuf);
-
-  if(!q_option && (x_option|d_option)){
-    if(x_option){
-      if(sizeof(KLONG)==4) printf("Address   Kbytes     RSS   Dirty Mode   Mapping\n");
-      else         printf("Address           Kbytes     RSS   Dirty Mode   Mapping\n");
-    }
-    if(d_option){
-      if(sizeof(KLONG)==4) printf("Address   Kbytes Mode  Offset           Device    Mapping\n");
-      else         printf("Address           Kbytes Mode  Offset           Device    Mapping\n");
-    }
-  }
-
-  while(fgets(mapbuf,sizeof mapbuf,fp)){
-    char flags[32];
-    char *tmp; // to clean up unprintables
-    unsigned KLONG start, end, diff=0;
-    unsigned long long file_offset, inode;
-    unsigned dev_major, dev_minor;
-    unsigned long long smap_value;
-    char smap_key[20];
-
-    /* hex values are lower case or numeric, keys are upper */
-    if (mapbuf[0] >= 'A' && mapbuf[0] <= 'Z') {
-      /* Its a key */
-      if (sscanf(mapbuf,"%20[^:]: %llu", smap_key, &smap_value) == 2) {
-        if (strncmp("Rss", smap_key, 3) == 0) {
-          rss = smap_value;
-          total_rss += smap_value;
-          continue;
-        }
-        if (strncmp("Shared_Dirty", smap_key, 12) == 0) {
-          shared_dirty = smap_value;
-          total_shared_dirty += smap_value;
-          continue;
-        }
-        if (strncmp("Private_Dirty", smap_key, 13) == 0) {
-          private_dirty = smap_value;
-          total_private_dirty += smap_value;
-          continue;
-        }
-        if (strncmp("Swap", smap_key, 4) == 0) { /*doesnt matter as long as last*/
-          printf(
-            (sizeof(KLONG)==8)
-              ? "%016"KLF"x %7lu %7llu %7llu %s  %s\n"
-              :      "%08lx %7lu %7llu %7llu %s  %s\n",
-            start,
-            (unsigned long)(diff>>10),
-            rss,
-            (private_dirty + shared_dirty),
-            flags,
-            cp2
-          );
-          /* reset some counters */
-          rss = shared_dirty = private_dirty = 0ull;
-          continue;
-        }
-        /* Other keys */
-        continue;
-      }
-    }
-    sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x %Lu", &start, &end, flags, &file_offset, &dev_major, &dev_minor, &inode);
-
-    if(start > range_high)
-      break;
-    if(end < range_low)
-      continue;
-
-    tmp = strchr(mapbuf,'\n');
-    if(tmp) *tmp='\0';
-    tmp = mapbuf;
-    while(*tmp){
-      if(!isprint(*tmp)) *tmp='?';
-      tmp++;
-    }
-    
-    diff = end-start;
-    if(flags[3]=='s') total_shared  += diff;
-    if(flags[3]=='p'){
-      flags[3] = '-';
-      if(flags[1]=='w') total_private_writeable += diff;
-      else              total_private_readonly  += diff;
-    }
-
-    // format used by Solaris 9 and procps-3.2.0+
-    // an 'R' if swap not reserved (MAP_NORESERVE, SysV ISM shared mem, etc.)
-    flags[4] = '-';
-    flags[5] = '\0';
-
-    if(x_option){
-          cp2 = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
-      /* printed with the keys */
-      continue;
-    }
-    if(d_option){
-      const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
-      printf(
-        (sizeof(KLONG)==8)
-          ? "%016"KLF"x %7lu %s %016Lx %03x:%05x %s\n"
-          :      "%08lx %7lu %s %016Lx %03x:%05x %s\n",
-        start,
-        (unsigned long)(diff>>10),
-        flags,
-        file_offset,
-        dev_major, dev_minor,
-        cp
-      );
-    }
-    if(!x_option && !d_option){
-      const char *cp = mapping_name(p, start, diff, mapbuf, 1, dev_major, dev_minor, inode);
-      printf(
-        (sizeof(KLONG)==8)
-          ? "%016"KLF"x %6luK %s  %s\n"
-          :      "%08lx %6luK %s  %s\n",
-        start,
-        (unsigned long)(diff>>10),
-        flags,
-        cp
-      );
-    }
-    
-  }
-
-
-
-
-  if(!q_option){
-    if(x_option){
-      if(sizeof(KLONG)==8){
-        printf("----------------  ------  ------  ------\n");
-        printf(
-          "total kB %15ld %7llu %7llu\n",
-          (total_shared + total_private_writeable + total_private_readonly) >> 10,
-          total_rss, (total_shared_dirty+total_private_dirty)
-
-        );
-      }else{
-        printf("-------- ------- ------- ------- -------\n");
-        printf(
-          "total kB %7ld       -       -       -\n",
-          (total_shared + total_private_writeable + total_private_readonly) >> 10
-        );
-      }
-    }
-    if(d_option){
-        printf(
-          "mapped: %ldK    writeable/private: %ldK    shared: %ldK\n",
-          (total_shared + total_private_writeable + total_private_readonly) >> 10,
-          total_private_writeable >> 10,
-          total_shared >> 10
-        );
-    }
-    if(!x_option && !d_option){
-      if(sizeof(KLONG)==8) printf(" total %16ldK\n", (total_shared + total_private_writeable + total_private_readonly) >> 10);
-      else                 printf(" total %8ldK\n",  (total_shared + total_private_writeable + total_private_readonly) >> 10);
-    }
-  }
-
-  return 0;
+static int one_proc(proc_t * p)
+{
+       char buf[32];
+       char mapbuf[9600];
+       char cmdbuf[512];
+       FILE *fp;
+       unsigned long total_shared = 0ul;
+       unsigned long total_private_readonly = 0ul;
+       unsigned long total_private_writeable = 0ul;
+
+       char *cp2 = NULL;
+       unsigned long long rss = 0ull;
+       unsigned long long private_dirty = 0ull;
+       unsigned long long shared_dirty = 0ull;
+       unsigned long long total_rss = 0ull;
+       unsigned long long total_private_dirty = 0ull;
+       unsigned long long total_shared_dirty = 0ull;
+
+       /* Overkill, but who knows what is proper? The "w" prog uses
+        * the tty width to determine this.
+        */
+       int maxcmd = 0xfffff;
+
+       sprintf(buf, "/proc/%u/maps", p->tgid);
+       if ((fp = fopen(buf, "r")) == NULL)
+               return 1;
+       if (x_option) {
+               sprintf(buf, "/proc/%u/smaps", p->tgid);
+               if ((fp = freopen(buf, "r", fp)) == NULL)
+                       return 1;
+       }
+
+       escape_command(cmdbuf, p, sizeof cmdbuf, &maxcmd,
+                      ESC_ARGS | ESC_BRACKETS);
+       printf("%u:   %s\n", p->tgid, cmdbuf);
+
+       if (!q_option && (x_option | d_option)) {
+               if (x_option) {
+                       if (sizeof(KLONG) == 4)
+                               printf
+                                   ("Address   Kbytes     RSS   Dirty Mode   Mapping\n");
+                       else
+                               printf
+                                   ("Address           Kbytes     RSS   Dirty Mode   Mapping\n");
+               }
+               if (d_option) {
+                       if (sizeof(KLONG) == 4)
+                               printf
+                                   ("Address   Kbytes Mode  Offset           Device    Mapping\n");
+                       else
+                               printf
+                                   ("Address           Kbytes Mode  Offset           Device    Mapping\n");
+               }
+       }
+
+       while (fgets(mapbuf, sizeof mapbuf, fp)) {
+               char flags[32];
+               /* to clean up unprintables */
+               char *tmp;
+               unsigned KLONG start, end, diff = 0;
+               unsigned long long file_offset, inode;
+               unsigned dev_major, dev_minor;
+               unsigned long long smap_value;
+               char smap_key[20];
+
+               /* hex values are lower case or numeric, keys are upper */
+               if (mapbuf[0] >= 'A' && mapbuf[0] <= 'Z') {
+                       /* Its a key */
+                       if (sscanf
+                           (mapbuf, "%20[^:]: %llu", smap_key,
+                            &smap_value) == 2) {
+                               if (strncmp("Rss", smap_key, 3) == 0) {
+                                       rss = smap_value;
+                                       total_rss += smap_value;
+                                       continue;
+                               }
+                               if (strncmp("Shared_Dirty", smap_key, 12) == 0) {
+                                       shared_dirty = smap_value;
+                                       total_shared_dirty += smap_value;
+                                       continue;
+                               }
+                               if (strncmp("Private_Dirty", smap_key, 13) == 0) {
+                                       private_dirty = smap_value;
+                                       total_private_dirty += smap_value;
+                                       continue;
+                               }
+                               if (strncmp("Swap", smap_key, 4) == 0) {
+                                       /*doesnt matter as long as last */
+                                       printf((sizeof(KLONG) == 8)
+                                              ? "%016" KLF
+                                              "x %7lu %7llu %7llu %s  %s\n" :
+                                              "%08lx %7lu %7llu %7llu %s  %s\n",
+                                              start,
+                                              (unsigned long)(diff >> 10), rss,
+                                              (private_dirty + shared_dirty),
+                                              flags, cp2);
+                                       /* reset some counters */
+                                       rss = shared_dirty = private_dirty =
+                                           0ull;
+                                       continue;
+                               }
+                               /* Other keys */
+                               continue;
+                       }
+               }
+               sscanf(mapbuf, "%" KLF "x-%" KLF "x %31s %Lx %x:%x %Lu", &start,
+                      &end, flags, &file_offset, &dev_major, &dev_minor,
+                      &inode);
+
+               if (start > range_high)
+                       break;
+               if (end < range_low)
+                       continue;
+
+               tmp = strchr(mapbuf, '\n');
+               if (tmp)
+                       *tmp = '\0';
+               tmp = mapbuf;
+               while (*tmp) {
+                       if (!isprint(*tmp))
+                               *tmp = '?';
+                       tmp++;
+               }
+
+               diff = end - start;
+               if (flags[3] == 's')
+                       total_shared += diff;
+               if (flags[3] == 'p') {
+                       flags[3] = '-';
+                       if (flags[1] == 'w')
+                               total_private_writeable += diff;
+                       else
+                               total_private_readonly += diff;
+               }
+               /* format used by Solaris 9 and procps-3.2.0+ an 'R'
+                * if swap not reserved (MAP_NORESERVE, SysV ISM
+                * shared mem, etc.)
+                */
+               flags[4] = '-';
+               flags[5] = '\0';
+
+               if (x_option) {
+                       cp2 =
+                           mapping_name(p, start, diff, mapbuf, 0, dev_major,
+                                        dev_minor, inode);
+                       /* printed with the keys */
+                       continue;
+               }
+               if (d_option) {
+                       const char *cp =
+                           mapping_name(p, start, diff, mapbuf, 0, dev_major,
+                                        dev_minor, inode);
+                       printf((sizeof(KLONG) == 8)
+                              ? "%016" KLF "x %7lu %s %016Lx %03x:%05x %s\n"
+                              : "%08lx %7lu %s %016Lx %03x:%05x %s\n",
+                              start,
+                              (unsigned long)(diff >> 10),
+                              flags, file_offset, dev_major, dev_minor, cp);
+               }
+               if (!x_option && !d_option) {
+                       const char *cp =
+                           mapping_name(p, start, diff, mapbuf, 1, dev_major,
+                                        dev_minor, inode);
+                       printf((sizeof(KLONG) == 8)
+                              ? "%016" KLF "x %6luK %s  %s\n"
+                              : "%08lx %6luK %s  %s\n",
+                              start, (unsigned long)(diff >> 10), flags, cp);
+               }
+
+       }
+
+       if (!q_option) {
+               if (x_option) {
+                       if (sizeof(KLONG) == 8) {
+                               printf
+                                   ("----------------  ------  ------  ------\n");
+                               printf("total kB %15ld %7llu %7llu\n",
+                                      (total_shared + total_private_writeable +
+                                       total_private_readonly) >> 10,
+                                      total_rss,
+                                      (total_shared_dirty +
+                                       total_private_dirty)
+
+                                   );
+                       } else {
+                               printf
+                                   ("-------- ------- ------- ------- -------\n");
+                               printf
+                                   ("total kB %7ld       -       -       -\n",
+                                    (total_shared + total_private_writeable +
+                                     total_private_readonly) >> 10);
+                       }
+               }
+               if (d_option) {
+                       printf
+                           ("mapped: %ldK    writeable/private: %ldK    shared: %ldK\n",
+                            (total_shared + total_private_writeable +
+                             total_private_readonly) >> 10,
+                            total_private_writeable >> 10, total_shared >> 10);
+               }
+               if (!x_option && !d_option) {
+                       if (sizeof(KLONG) == 8)
+                               printf(" total %16ldK\n",
+                                      (total_shared + total_private_writeable +
+                                       total_private_readonly) >> 10);
+                       else
+                               printf(" total %8ldK\n",
+                                      (total_shared + total_private_writeable +
+                                       total_private_readonly) >> 10);
+               }
+       }
+
+       return 0;
 }
 
-
-int main(int argc, char *argv[]){
-  unsigned *pidlist;
-  unsigned count = 0;
-  PROCTAB* PT;
-  proc_t p;
-  int ret = 0;
-
-  if(argc<2) usage();
-  pidlist = malloc(sizeof(unsigned)*argc);  // a bit more than needed perhaps
-
-  while(*++argv){
-    if(!strcmp("--version",*argv)){
-      V_option++;
-      continue;
-    }
-    if(**argv=='-'){
-      char *walk = *argv;
-      if(!walk[1]) usage();
-      while(*++walk){
-        switch(*walk){
-        case 'V':
-          V_option++;
-          break;
-        case 'x':
-          x_option++;
-          break;
-        case 'r':
-          r_option++;
-          break;
-        case 'd':
-          d_option++;
-          break;
-        case 'q':
-          q_option++;
-          break;
-        case 'A':{
-            char *arg1;
-            if(walk[1]){
-              arg1 = walk+1;
-              walk += strlen(walk)-1;
-            }else{
-              arg1 = *++argv;
-              if(!arg1)
-                usage();
-            }
-            char *arg2 = strchr(arg1,',');
-            if(arg2)
-              *arg2 = '\0';
-            if(arg2) ++arg2;
-            else arg2 = arg1;
-            
-            if(*arg1)
-              range_low = STRTOUKL(arg1,&arg1,16);
-            if(*arg2)
-              range_high = STRTOUKL(arg2,&arg2,16);
-            if(*arg1 || *arg2)
-              usage();
-          }
-          break;
-        case 'a': // Sun prints anon/swap reservations
-        case 'F': // Sun forces hostile ptrace-like grab
-        case 'l': // Sun shows unresolved dynamic names
-        case 'L': // Sun shows lgroup info
-        case 's': // Sun shows page sizes
-        case 'S': // Sun shows swap reservations
-        default:
-          usage();
-        }
-      }
-    }else{
-      char *walk = *argv;
-      char *endp;
-      unsigned long pid;
-      if(!strncmp("/proc/",walk,6)){
-        walk += 6;
-        // user allowed to do: pmap /proc/*
-        if(*walk<'0' || *walk>'9') continue;
-      }
-      if(*walk<'0' || *walk>'9') usage();
-      pid = strtoul(walk, &endp, 0);
-      if(pid<1ul || pid>0x7ffffffful || *endp) usage();
-      pidlist[count++] = pid;
-    }
-  }
-
-  if( (x_option|V_option|r_option|d_option|q_option) >> 1 ) usage(); // dupes
-  if(V_option){
-    if(count|x_option|r_option|d_option|q_option) usage();
-    fprintf(stdout, "pmap (%s)\n", procps_version);
-    return 0;
-  }
-  if(count<1) usage();   // no processes
-  if(d_option && x_option) usage();
-
-  discover_shm_minor();
-
-  memset(&p, '\0', sizeof(p));
-  pidlist[count] = 0;  // old libproc interface is zero-terminated
-  PT = openproc(PROC_FILLSTAT|PROC_FILLARG|PROC_PID, pidlist);
-  while(readproc(PT, &p)){
-    ret |= one_proc(&p);
-    count--;
-  }
-  closeproc(PT);
-
-  if(count) ret |= 42;  // didn't find all processes asked for
-  return ret;
+int main(int argc, char **argv)
+{
+       unsigned *pidlist;
+       unsigned count = 0;
+       PROCTAB *PT;
+       proc_t p;
+       int ret = 0, c;
+
+       static const struct option longopts[] = {
+               {"extended", no_argument, NULL, 'x'},
+               {"device", no_argument, NULL, 'd'},
+               {"quiet", no_argument, NULL, 'q'},
+               {"range", required_argument, NULL, 'A'},
+               {"help", no_argument, NULL, 'h'},
+               {"version", no_argument, NULL, 'V'},
+               {NULL, 0, NULL, 0}
+       };
+
+       x_option = d_option = q_option = 0;
+
+       while ((c = getopt_long(argc, argv, "xrdqA:hV", longopts, NULL)) != -1)
+               switch (c) {
+               case 'x':
+                       x_option = 1;
+                       break;
+               case 'r':
+                       warnx("option -r is ignored as SunOS compatibility");
+                       break;
+               case 'd':
+                       d_option = 1;
+                       break;
+               case 'q':
+                       q_option = 1;
+                       break;
+               case 'A':
+                       {
+                               /* FIXME: this should be a function. */
+                               char *walk = optarg;
+                               char *arg1;
+                               char *arg2;
+                               if (walk[1]) {
+                                       arg1 = walk + 1;
+                                       walk += strlen(walk) - 1;
+                               } else {
+                                       arg1 = *++argv;
+                                       if (!arg1)
+                                               usage(stderr);
+                               }
+                               arg2 = strchr(arg1, ',');
+                               if (arg2)
+                                       *arg2 = '\0';
+                               arg2 = *arg2 ? arg2++ : arg1;
+
+                               if (*arg1)
+                                       range_low = STRTOUKL(arg1, &arg1, 16);
+                               if (*arg2)
+                                       range_high = STRTOUKL(arg2, &arg2, 16);
+                               if (*arg1 || *arg2)
+                                       usage(stderr);
+                       }
+                       break;
+               case 'h':
+                       usage(stdout);
+               case 'V':
+                       display_version();
+                       return EXIT_SUCCESS;
+               case 'a':       /* Sun prints anon/swap reservations */
+               case 'F':       /* Sun forces hostile ptrace-like grab */
+               case 'l':       /* Sun shows unresolved dynamic names */
+               case 'L':       /* Sun shows lgroup info */
+               case 's':       /* Sun shows page sizes */
+               case 'S':       /* Sun shows swap reservations */
+               default:
+                       usage(stderr);
+               }
+
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 1)
+               errx(EXIT_FAILURE, "argument missing");
+       if (d_option && x_option)
+               errx(EXIT_FAILURE, "options -d and -x can not coexist");
+
+       pidlist = malloc(sizeof(unsigned) * argc);
+       if (pidlist == NULL)
+               err(EXIT_FAILURE, "cannot allocate %zu bytes",
+                   sizeof(unsigned) * argc);
+
+       while (*argv) {
+               char *walk = *argv++;
+               char *endp;
+               unsigned long pid;
+               if (!strncmp("/proc/", walk, 6)) {
+                       walk += 6;
+                       /*  user allowed to do: pmap /proc/PID */
+                       if (*walk < '0' || *walk > '9')
+                               continue;
+               }
+               if (*walk < '0' || *walk > '9')
+                       usage(stderr);
+               pid = strtoul(walk, &endp, 0);
+               if (pid < 1ul || pid > 0x7ffffffful || *endp)
+                       usage(stderr);
+               pidlist[count++] = pid;
+       }
+
+       discover_shm_minor();
+
+       memset(&p, '\0', sizeof(p));
+       /* old libproc interface is zero-terminated */
+       pidlist[count] = 0;
+       PT = openproc(PROC_FILLSTAT | PROC_FILLARG | PROC_PID, pidlist);
+       while (readproc(PT, &p)) {
+               ret |= one_proc(&p);
+               count--;
+       }
+       closeproc(PT);
+
+       if (count)
+               /* didn't find all processes asked for */
+               ret |= 42;
+       return ret;
 }