procps/procps-3.2.8-pmap-smaps-rml-2.patch

851 lines
22 KiB
Diff
Raw Normal View History

--- pmap.1
+++ pmap.1 2009-05-11 12:14:59.377902682 +0200
@@ -1,39 +1,60 @@
-'\" t
-.\" (The preceding line is a note to broken versions of man to tell
-.\" them to pre-process this man page with tbl)
-.\" Man page for pmap.
-.\" Licensed under version 2 of the GNU General Public License.
-.\" Written by Albert Cahalan.
+.\" pmap.1 - manpage for the pmap(1) utility, part of procps
.\"
-.TH PMAP 1 "October 26, 2002" "Linux" "Linux User's Manual"
+.\" Copyright (C) 2005 Robert Love
+.\" Licensed under the terms of the GNU General Public License, v2
+.TH PMAP 1 "12 Oct 2005" "Linux" "Linux User's Manual"
.SH NAME
-pmap \- report memory map of a process
+pmap \- display information about process memory mappings
.SH SYNOPSIS
-.nf
-pmap [ -x | -d ] [ -q ] pids...
-pmap -V
-.fi
+.BI "pmap [ \-d | \-q | \-h | \-V | \-A\ low,high ] " pid
.SH DESCRIPTION
-The pmap command reports the memory map of a process or processes.
-
-.SH "GENERAL OPTIONS"
-.TS
-l l l.
--x extended Show the extended format.
--d device Show the device format.
--q quiet Do not display some header/footer lines.
--V show version Displays version of program.
-.TE
+.BR pmap (1)
+displays information about a process's memory mappings, such as its stack,
+data segment, mapped files, and so on.
+.P
+The
+.BR pmap (1)
+utility will show, for each mapping of a given process, the starting byte
+address in the process's address space, the size, the RSS (size of the mapping
+in physical memory), the amount of dirty pages, the permission, the device node,
+the offset, and the file backing the mapping, if any.
+.P
+As the last line of output, the
+.BR pmap (1)
+utility will tally up the total size of all mappings as well as show the
+total size of writable/private mappings and of shared mappings.
+
+.SH OPTIONS
+.TP
+.B\-d, \-\^\-device
+Display major and minor device numbers.
+.TP
+.B\-A, \-\-limit=low,high
+Limit results to the given range.
+.TP
+.B\-q, \-\^\-quiet
+Hide header and memory statistics.
+.TP
+.B\-h, \-\^\-help
+Show pmap usage.
+.TP
+.B\-V, \-\^\-version
+Display version information.
+
+.SH FILES
+.IR /proc/pid/maps " and
+.IR /proc/pid/smaps " \-\- memory mapping information"
.SH "SEE ALSO"
-ps(1) pgrep(1)
+.BR ps (1),
+.BR top (1),
+.BR free (1),
+.BR vmstat (1)
-.SH STANDARDS
-No standards apply, but pmap looks an awful lot like a SunOS command.
+.SH AUTHORS
+Written by Chris Rivera.
-.SH AUTHOR
-Albert Cahalan <albert@users.sf.net> wrote pmap in 2002, and is the current
-maintainer of the procps collection. Please send bug reports
-to <procps-feedback@lists.sf.net>.
+The procps package is maintained by Albert Calahan. Please send
+bug reports to <albert@users.sf.net>.
--- pmap.c
+++ pmap.c 2009-06-16 16:28:36.169902773 +0200
@@ -1,372 +1,405 @@
/*
- * Copyright 2002 by Albert Cahalan; all rights reserved.
- * This file may be used subject to the terms and conditions of the
- * GNU Library General Public License Version 2, or any later version
- * at your option, as published by the Free Software Foundation.
- * 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 Library General Public License for more details.
+ * pmap - print the address space map of a process
+ *
+ * Chris Rivera <chrismrivera@gmail.com>
+ * Robert Love <rml@novell.com>
+ * Werner Fink <werner@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, v2, as
+ * published by the Free Software Foundation
+ *
+ * Copyright (C) 2003, 2005 Chris Rivera
+ * Copyright (C) 2009 Werner Fink
*/
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/utsname.h>
#include <unistd.h>
-#include <sys/ipc.h>
-#include <sys/shm.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 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 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;
- }
- }
+#define BUFFERSIZE 4096
+#define OBJECTSIZE 1024
- if(shmdt(addr)) perror("shmdt");
-
-out_destroy:
- if(shmctl(shmid, IPC_RMID, NULL)) perror("IPC_RMID");
+struct smap {
+ unsigned long size;
+ unsigned long rss;
+ unsigned long pss;
+ unsigned long shared_clean;
+ unsigned long shared_dirty;
+ unsigned long private_clean;
+ unsigned long private_dirty;
+ unsigned long referenced;
+ unsigned long swap;
+};
+
+static unsigned long long range_low;
+static unsigned long long range_high = ~0ULL;
+static unsigned long mapped;
+static unsigned long shared;
+static unsigned long private;
+static unsigned long rss;
+static unsigned long pss;
+static unsigned long dirty;
+static unsigned long referenced;
+static unsigned long swap;
+static FILE *smaps_fp;
+static int maj, min, patch, dopss, noref, doswap, dopage;
+static long lbits;
+#define BLK ((lbits==64)?" ":"")
+#define WDT ((lbits==64)?16:8)
+
+static void usage(const char *cmd)
+{
+ fprintf(stderr, "usage: %s [options] pid\n", cmd);
+ fprintf(stderr, " -d, --device "
+ "display offset and device numbers\n");
+ fprintf(stderr, " -q, --quiet "
+ "hide header and memory statistics\n");
+ fprintf(stderr, " -A, --limit=low,high "
+ "limit results to the given range\n");
+ fprintf(stderr, " -V, --version "
+ "display version information\n");
+ fprintf(stderr, " -h, --help "
+ "display this help\n");
+}
- return;
+static int get_smap_data(struct smap *smap)
+{
+ unsigned long long data;
+ int assigned;
+ char buff[BUFFERSIZE];
+
+ /* get main line */
+ if (!fgets(buff, BUFFERSIZE - 1, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "%llx-", &data);
+ if (assigned != 1)
+ return 1;
+
+ /* get size */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Size: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->size = data;
+
+ /* get rss */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Rss: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->rss = data;
+ rss += data;
+
+ if (dopss) {
+ /* get pss */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Pss: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->pss = data;
+ pss += data;
+ }
+
+ /* get shared clean */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Shared_Clean: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->shared_clean = data;
+
+ /* get shared dirty */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Shared_Dirty: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->shared_dirty = data;
+ dirty += data;
+
+ /* get private clean */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Private_Clean: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->private_clean = data;
+
+ /* get private dirty */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Private_Dirty: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->private_dirty = data;
+ dirty += data;
+
+ if (noref)
+ goto out;
+
+ /* get referenced */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Referenced: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->referenced = data;
+ referenced += data;
+
+ if (!doswap)
+ goto out;
+
+ /* get swap */
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+
+ assigned = sscanf(buff, "Swap: %lld", &data);
+ if (assigned != 1)
+ return 1;
+ smap->swap = data;
+ swap += data;
+
+ if (!dopage)
+ goto out;
+
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+ if (!fgets(buff, BUFFERSIZE, smaps_fp))
+ return 1;
+out:
+ return 0;
}
+static void parse_line(pid_t pid, const char *line, int show_devices)
+{
+ unsigned long long low, high, size, offset;
+ unsigned long major, minor;
+ struct smap smap = { .rss = 0, .pss = 0 };
+ int assigned;
+ char read_perm, write_perm, exec_perm, access_type;
+ char obj_buff[OBJECTSIZE] = "[anon]";
+
+ assigned = sscanf(line, "%llx-%llx %c%c%c%c %llx %lx:%lx %*u %"
+ STRINGIFY(OBJECTSIZE) "s", &low, &high, &read_perm,
+ &write_perm, &exec_perm, &access_type, &offset, &major,
+ &minor, obj_buff);
+
+ if (assigned < 9) {
+ fprintf(stderr, "failed to parse /proc/%d/maps\n", pid);
+ exit(EXIT_FAILURE);
+ }
+
+ size = high - low;
+ size /= 1024;
+ mapped += size;
+
+ if (smaps_fp && get_smap_data(&smap)) {
+ fprintf(stderr, "failed to parse /proc/%d/smaps\n", pid);
+ exit(1);
+ }
+
+ if (access_type == 's')
+ shared += size;
+ else if (access_type == 'p' && write_perm == 'w')
+ private += size;
+
+ if(low > range_high)
+ return;
+ if(high < range_low)
+ return;
+
+ printf("%0*llx %6lluK ", WDT, low, size);
+
+ if (smaps_fp) {
+ printf("%6luK ", smap.rss);
+ if (dopss)
+ printf("%6luK ", smap.pss);
+ printf("%6luK ", smap.private_dirty + smap.shared_dirty);
+ if (doswap)
+ printf("%6luK ", smap.swap);
+ }
-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;
+ printf("%c%c%c%c ", read_perm, write_perm, exec_perm, access_type);
- 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;
-}
+ if (show_devices)
+ printf("%0*llx %02lx:%02lx ", WDT, offset, major, minor);
-static int one_proc(proc_t *p){
- char buf[32];
- char mapbuf[9600];
- char cmdbuf[512];
- unsigned long total_shared = 0ul;
- unsigned long total_private_readonly = 0ul;
- unsigned long total_private_writeable = 0ul;
-
- // 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(!freopen(buf, "r", stdin)) 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 Anon Locked Mode Mapping\n");
- else printf("Address Kbytes RSS Anon Locked 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,stdin)){
- char flags[32];
- char *tmp; // to clean up unprintables
- unsigned KLONG start, end, diff;
- 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);
-
- 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){
- const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
- printf(
- (sizeof(KLONG)==8)
- ? "%016"KLF"x %7lu - - - %s %s\n"
- : "%08lx %7lu - - - %s %s\n",
- start,
- (unsigned long)(diff>>10),
- flags,
- cp
- );
- }
- 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 - - -\n",
- (total_shared + total_private_writeable + total_private_readonly) >> 10
- );
- }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;
+ printf("%s\n", obj_buff);
}
+int main(int argc, char *argv[])
+{
+ proc_t proc;
+ FILE *fp;
+ char path[PATH_MAX];
+ char buff[BUFFERSIZE];
+ int o, show_devices = 0, quiet = 0;
+ struct utsname uts;
+ pid_t pid;
+
+ if (uname(&uts) < 0) {
+ fprintf(stderr, "error getting information about current kernel: %m\n");
+ exit(EXIT_FAILURE);
+ }
+ sscanf(uts.release, "%d.%d.%d", &maj, &min, &patch);
+
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 30)))))
+ dopage++;
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 27)))))
+ doswap++;
+ if ((maj > 2) || ((maj == 2) && ((min > 6) || ((min == 6) && (patch >= 25)))))
+ dopss++;
+ if ((maj < 2) || ((maj == 2) && ((min < 6) || ((min == 6) && (patch < 22)))))
+ noref++;
+
+ if ((lbits = sysconf(_SC_LONG_BIT)) < 0) {
+ fprintf(stderr, "error getting information about current kernel: %m\n");
+ exit(EXIT_FAILURE);
+ }
+
+ struct option longopts[] = {
+ { "help", 0, NULL, 'h' },
+ { "version", 0, NULL, 'V' },
+ { "quiet", 0, NULL, 'q' },
+ { "device", 0, NULL, 'd' },
+ { "limit", 0, NULL, 'A' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ while ((o = getopt_long(argc, argv, "hqdA:V", longopts, NULL)) != -1) {
+ switch (o) {
+ case 'V':
+ display_version();
+ return 0;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'd':
+ show_devices = 1;
+ break;
+ case 'A':
+ if (!optarg || *optarg == 0) {
+ usage(argv[0]);
+ return 1;
+ } else {
+ char *low = optarg;
+ char *high = strchr(low, ',');
+ if (high) {
+ *high = '\0';
+ high++;
+ }
+ if (low)
+ range_low = strtoull(low, &low, 16);
+ if (high)
+ range_high = strtoull(high, &high, 16);
+ if (*low || *high) {
+ usage(argv[0]);
+ return 1;
+ }
+ }
+ break;
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+ if (argc - optind > 0) {
+ errno = 0;
+ pid = strtoul(argv[optind], NULL, 10);
+ if (errno) {
+ perror("strtoul");
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!get_proc_stats(pid, &proc)) {
+ fprintf(stderr, "error getting process information for pid "
+ "%d from /proc/%d\n", pid, pid);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%d: %s\n", pid, proc.cmd);
+
+ snprintf(path, PATH_MAX, "/proc/%d/maps", pid);
+ fp = fopen(path, "r");
+ if (!fp) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ snprintf(path, PATH_MAX, "/proc/%d/smaps", pid);
+ smaps_fp = fopen(path, "r");
+
+ if (!quiet) {
+ printf("START%s SIZE ", BLK);
+
+ if (smaps_fp) {
+ printf(" RSS ");
+ if (dopss)
+ printf(" PSS ");
+ printf(" DIRTY ");
+ if (doswap)
+ printf(" SWAP ");
+ }
+
+ if (show_devices)
+ printf("PERM OFFSET DEVICE MAPPING\n");
+ else
+ printf("PERM MAPPING\n");
+ }
+
+ while (fgets(buff, BUFFERSIZE - 1, fp))
+ parse_line(pid, buff, show_devices);
+
+ if (!quiet) {
+ if (smaps_fp) {
+ printf("Total:%s ", BLK);
+ printf(" %6luK", mapped);
+ printf(" %6luK", rss);
+ if (dopss)
+ printf(" %6luK", pss);
+ printf(" %6luK", dirty);
+ if (doswap)
+ printf(" %6luK", swap);
+ printf("\n\n");
+ } else
+ printf("mapped: %luK ", mapped);
+
+ if (noref)
+ printf("%luK writable-private, %luK readonly-private, and %luK shared\n",
+ private, mapped - private - shared, shared);
+ else
+ printf("%luK writable-private, %luK readonly-private, %luK shared, and %luK referenced\n",
+ private, mapped - private - shared, shared, referenced);
+ }
-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';
- arg2 = arg2 ? 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();
-
- 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);
- if(p.cmdline) free((void*)*p.cmdline);
- count--;
- }
- closeproc(PT);
-
- if(count) ret |= 42; // didn't find all processes asked for
- return ret;
+ return 0;
}