procps/pmap.c

251 lines
6.5 KiB
C
Raw Normal View History

2002-10-27 16:14:05 +05:30
/*
* Copyright 2002 by Albert Cahalan; all rights reserved.
2002-10-27 16:14:05 +05:30
* 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.
*/
2002-02-02 04:17:29 +05:30
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
2002-10-27 16:05:13 +05:30
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
2004-01-27 01:31:56 +05:30
#include "proc/readproc.h"
#include "proc/version.h"
2002-02-02 04:17:29 +05:30
2002-12-09 13:23:09 +05:30
static void usage(void) NORETURN;
2002-10-27 16:05:13 +05:30
static void usage(void){
2002-02-02 04:17:29 +05:30
fprintf(stderr,
"Usage: pmap [-r] [-x] pid...\n"
"-x show details\n"
);
exit(1);
}
2002-10-27 16:05:13 +05:30
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];
2002-02-02 04:17:29 +05:30
char buf[32];
int fd;
2002-10-27 16:05:13 +05:30
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
}
2004-01-27 01:31:56 +05:30
static const char *anon_name(int pid, unsigned KLONG addr, unsigned KLONG len){
const char *cp = " [ anon ]";
proc_t proc;
if (get_proc_stats(pid, &proc)){
if( (proc.start_stack >= addr) && (proc.start_stack <= addr+len) ) cp = " [ stack ]";
}
return cp;
}
2002-10-27 16:05:13 +05:30
static int one_proc(unsigned pid){
char buf[32];
char mapbuf[9600];
unsigned long total_shared = 0ul;
unsigned long total_private = 0ul;
2002-02-02 04:17:29 +05:30
sprintf(buf,"/proc/%u/maps",pid);
2002-10-27 16:05:13 +05:30
if(!freopen(buf, "r", stdin)) return 1;
printf("%u: %s\n", pid, get_args(pid));
2002-02-02 04:17:29 +05:30
if(x_option)
2002-10-27 16:05:13 +05:30
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
2004-01-27 01:31:56 +05:30
unsigned KLONG start, end, diff;
2002-10-27 16:05:13 +05:30
unsigned long long pgoff;
2004-01-27 01:31:56 +05:30
sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx", &start, &end, flags, &pgoff);
2002-10-27 16:05:13 +05:30
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++;
2004-01-27 01:31:56 +05:30
if(!cp) cp = anon_name(pid, start, diff);
2002-10-27 16:05:13 +05:30
printf(
2004-01-27 01:31:56 +05:30
(sizeof(KLONG)==8)
? "%016"KLF"x %7lu - %7lu %7lu %s %s\n"
: "%08lx %7lu - %7lu %7lu %s %s\n",
2002-10-27 16:05:13 +05:30
start,
2004-01-27 01:31:56 +05:30
(unsigned long)(diff>>10),
(flags[3]=='s') ? (unsigned long)(diff>>10) : 0,
(flags[3]=='p') ? (unsigned long)(diff>>10) : 0,
2002-10-27 16:05:13 +05:30
perms,
cp
);
}else{
const char *cp = strchr(mapbuf,'/');
2004-01-27 01:31:56 +05:30
if(!cp) cp = anon_name(pid, start, diff);
2002-10-27 16:05:13 +05:30
printf(
2004-01-27 01:31:56 +05:30
(sizeof(KLONG)==8)
? "%016"KLF"x %6luK %s %s\n"
: "%08lx %6luK %s %s\n",
2002-10-27 16:05:13 +05:30
start,
2004-01-27 01:31:56 +05:30
(unsigned long)(diff>>10),
2002-10-27 16:05:13 +05:30
perms,
cp
);
}
}
if(x_option){
2004-01-27 01:31:56 +05:30
if(sizeof(KLONG)==8){
2002-10-27 16:05:13 +05:30
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{
2004-01-27 01:31:56 +05:30
if(sizeof(KLONG)==8) printf(" total %16ldK\n", (total_shared + total_private) >> 10);
else printf(" total %8ldK\n", (total_shared + total_private) >> 10);
2002-10-27 16:05:13 +05:30
}
return 0;
2002-02-02 04:17:29 +05:30
}
2002-10-27 16:05:13 +05:30
2002-02-02 04:17:29 +05:30
int main(int argc, char *argv[]){
2002-10-27 16:05:13 +05:30
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;
2004-01-27 01:31:56 +05:30
if(!strncmp("/proc/",walk,6)){
walk += 6;
// user allowed to do: pmap /proc/*
if(*walk<'0' || *walk>'9') continue;
}
2002-10-27 16:05:13 +05:30
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<count) ret |= one_proc(pidlist[u++]);
return ret;
2002-02-02 04:17:29 +05:30
}