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