diff --git a/Makefile b/Makefile index ed079d23..065c4239 100644 --- a/Makefile +++ b/Makefile @@ -47,12 +47,12 @@ usr/include := $(DESTDIR)/usr/include/ BINFILES := $(usr/bin)uptime $(usr/bin)tload $(usr/bin)free $(usr/bin)w \ $(usr/bin)top $(usr/bin)vmstat $(usr/bin)watch $(usr/bin)skill \ - $(usr/bin)snice $(bin)kill $(sbin)sysctl \ + $(usr/bin)snice $(bin)kill $(sbin)sysctl $(usr/bin)pmap \ $(usr/proc/bin)pgrep $(usr/proc/bin)pkill MANFILES := $(man1)uptime.1 $(man1)tload.1 $(man1)free.1 $(man1)w.1 \ $(man1)top.1 $(man1)watch.1 $(man1)skill.1 $(man1)kill.1 \ - $(man1)snice.1 $(man1)pgrep.1 $(man1)pkill.1 \ + $(man1)snice.1 $(man1)pgrep.1 $(man1)pkill.1 $(man1)pmap.1 \ $(man5)sysctl.conf.5 $(man8)vmstat.8 $(man8)sysctl.8 TARFILES := AUTHORS BUGS NEWS README TODO COPYING COPYING.LIB ChangeLog \ @@ -146,7 +146,7 @@ w.o: w.c ############ prog.o --> prog -w uptime tload free vmstat utmp pgrep skill: % : %.o $(LIBPROC) +pmap w uptime tload free vmstat utmp pgrep skill: % : %.o $(LIBPROC) $(CC) $(LDFLAGS) -o $@ $^ top: % : %.o $(LIBPROC) diff --git a/NEWS b/NEWS index a215e892..dba3d7ad 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +procps-3.0.5 --> procps-3.0.6 + +can build w/o shared library (set SHARED=0) +when IO-wait hidden, count as idle, not as sys +pmap command added (like Sun has) + procps-3.0.4 --> procps-3.0.5 top tolerates super-wide displays diff --git a/pmap.1 b/pmap.1 new file mode 100644 index 00000000..930fd6b5 --- /dev/null +++ b/pmap.1 @@ -0,0 +1,36 @@ +'\" 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. +.\" +.TH PMAP 1 "October 26, 2002" "Linux" "Linux User's Manual" +.SH NAME +pmap \- report memory map of a process + +.SH SYNOPSIS +.nf +pmap [-x] [-V] pids... +.fi + +.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. +-V show version Displays version of program. +.TE + +.SH "SEE ALSO" +ps(1) pgrep(1) + +.SH STANDARDS +No standards apply, but pmap looks an awful lot like a SunOS command. + +.SH AUTHOR +Albert Cahalan wrote pmap in 2002, and is the current +maintainer of the procps collection. Please send bug reports +to . diff --git a/pmap.c b/pmap.c index ad01e1ec..db8c3678 100644 --- a/pmap.c +++ b/pmap.c @@ -1,34 +1,225 @@ #include #include #include +#include +#include +#include +#include +#include +#include "proc/version.h" // FIXME: we need to link the lib for this :-( -void usage(void){ +static void usage(void){ fprintf(stderr, "Usage: pmap [-r] [-x] pid...\n" - "-r ignored (compatibility option)\n" "-x show details\n" ); exit(1); } -int one_proc(unsigned pid){ - char cmdbuf[64]; + +static int V_option; +static int r_option; // ignored -- for SunOS compatibility +static int x_option; + + +static const char *get_args(unsigned pid){ + static char cmdbuf[64]; char buf[32]; int fd; - sprintf(buf,"/proc/%u/cmdline",pid); - if( ((fd=open(buf)) == -1) return 1; - count = read(fd, cmdbuf, sizeof(cmdbuf)-1); - if(count<1) return 1; - cmdbuf[count] = '\0'; - while(count--) if(!isprint(cmdbuf[count])) cmdbuf[count]=' '; - close(fd); - sprintf(buf,"/proc/%u/maps",pid); - if( ((fd=open(buf)) == -1) return 1; - printf("%u: %s\n", pid, cmdbuf); - if(x_option) - printf("Address kB Resident Shared Private Permissions Name\n"); -@@@ FIXME FIXME FIXME @@@ + ssize_t count; + + do{ + sprintf(buf,"/proc/%u/cmdline",pid); + if( (( fd=open(buf,O_RDONLY) )) == -1) break; + count = read(fd, cmdbuf, sizeof(cmdbuf)-1); + close(fd); + if(count<1) break; + cmdbuf[count] = '\0'; + if(!isprint(cmdbuf[0])) break; + while(count--) if(!isprint(cmdbuf[count])) cmdbuf[count]=' '; + return cmdbuf; + }while(0); + + do{ + char *cp; + sprintf(buf,"/proc/%u/stat",pid); + if( (( fd=open(buf,O_RDONLY) )) == -1) break; + count = read(fd, cmdbuf, sizeof(cmdbuf)-1); + close(fd); + if(count<1) break; + cmdbuf[count] = '\0'; + while(count--) if(!isprint(cmdbuf[count])) cmdbuf[count]=' '; + cp = strrchr(cmdbuf,')'); + if(!cp) break; + cp[0] = ']'; + cp[1] = '\0'; + cp = strchr(cmdbuf,'('); + if(!cp) break; + if(!isprint(cp[1])) break; + cp[0] = '['; + return cp; + }while(0); + + return "[]"; // as good as anything } -int main(int argc, char *argv[]){ + +static int one_proc(unsigned pid){ + char buf[32]; + char mapbuf[9600]; + unsigned long total_shared = 0ul; + unsigned long total_private = 0ul; + + sprintf(buf,"/proc/%u/maps",pid); + if(!freopen(buf, "r", stdin)) return 1; + printf("%u: %s\n", pid, get_args(pid)); + if(x_option) + printf("Address kB Resident Shared Private Permissions Name\n"); + while(fgets(mapbuf,sizeof mapbuf,stdin)){ + char flags[32]; + const char *perms; + char *tmp; // to clean up unprintables + unsigned long start, end, diff; + unsigned long long pgoff; + sscanf(mapbuf,"%lx-%lx %s %Lx", &start, &end, flags, &pgoff); + tmp = strchr(mapbuf,'\n'); + if(tmp) *tmp='\0'; + tmp = mapbuf; + while(*tmp){ + if(!isprint(*tmp)) *tmp='?'; + tmp++; + } + + if(flags[0]=='r'){ + if(flags[1]=='w'){ + if(flags[2]=='x') perms = "read/write/exec"; + else perms = "read/write "; + }else{ + if(flags[2]=='x') perms = "read/exec "; + else perms = "read "; + } + }else{ + if(flags[1]=='w'){ + if(flags[2]=='x') perms = "write/exec "; + else perms = "write "; + }else{ + if(flags[2]=='x') perms = "exec "; + else perms = "none "; + } + } + diff = end-start; + if(flags[3]=='s') total_shared += diff; + if(flags[3]=='p') total_private += diff; + if(x_option){ + const char *cp = strrchr(mapbuf,'/'); + if(cp && cp[1]) cp++; + if(!cp) cp = " [ anon ]"; // yeah, 1 space + printf( + (sizeof(long)==8) + ? "%016lx %7ld - %7ld %7ld %s %s\n" + : "%08lx %7ld - %7ld %7ld %s %s\n", + start, + diff>>10, + (flags[3]=='s') ? diff>>10 : 0, + (flags[3]=='p') ? diff>>10 : 0, + perms, + cp + ); + }else{ + const char *cp = strchr(mapbuf,'/'); + if(!cp) cp = " [ anon ]"; // yeah, 2 spaces + printf( + (sizeof(long)==8) + ? "%016lx %6ldK %s %s\n" + : "%08lx %6ldK %s %s\n", + start, + diff>>10, + perms, + cp + ); + } + + } + if(x_option){ + if(sizeof(long)==8){ + printf("---------------- ------ ------ ------ ------\n"); + printf( + "total kB %15ld - %7ld %7ld\n", + (total_shared + total_private) >> 10, + total_shared >> 10, + total_private >> 10 + ); + }else{ + printf("-------- ------ ------ ------ ------\n"); + printf( + "total kB %7ld - %7ld %7ld\n", + (total_shared + total_private) >> 10, + total_shared >> 10, + total_private >> 10 + ); + } + }else{ + if(sizeof(long)==8) printf(" total %16ldK\n", (total_shared + total_private) >> 10); + else printf(" total %8ldK\n", (total_shared + total_private) >> 10); + } + return 0; +} + + +int main(int argc, char *argv[]){ + unsigned *pidlist; + unsigned count = 0; + unsigned u; + 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; + default: + usage(); + } + } + }else{ + char *walk = *argv; + char *endp; + unsigned long pid; + if(!strncmp("/proc/",walk,6)) walk += 6; + if(*walk<'0' || *walk>'9') usage(); + pid = strtoul(walk, &endp, 0); + if(pid<1ul || pid>0x7ffffffful || *endp) usage(); + pidlist[count++] = pid; + } + } + + if(x_option>1 || V_option>1 || r_option>1) usage(); // dupes + if(V_option){ + if(count|x_option|r_option) usage(); + fprintf(stdout, "pmap (%s)\n", procps_version); + return 0; + } + if(count<1) usage(); // no processes + + u=0; + while(u