#include <fcntl.h>
#include <string.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){
static int q_option;
-static const char *get_args(unsigned pid){
- static char cmdbuf[64];
- char buf[32];
- int fd;
- 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);
+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;
- return "[]"; // as good as anything
+ 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 const char *anon_name(int pid, unsigned KLONG addr, unsigned KLONG len){
- const char *cp = " [ anon ]";
- proc_t proc;
- static int oldpid = -1;
- if (pid==oldpid || get_proc_stats(pid, &proc)){
- oldpid = pid;
- if( (proc.start_stack >= addr) && (proc.start_stack <= addr+len) ) cp = " [ stack ]";
+
+static const char *mapping_name(proc_t *p, unsigned KLONG addr, unsigned KLONG len, const char *mapbuf, unsigned advance, 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(cp[1]) cp += advance;
+ return cp;
}
+
+ cp = " [ anon ]";
+ if( (p->start_stack >= addr) && (p->start_stack <= addr+len) ) cp = " [ stack ]";
return cp;
}
-static int one_proc(unsigned pid){
+
+// Overkill, but who knows what is proper? The "w" prog
+// uses the tty width to determine this.
+#define maxcmd 0xfffff
+
+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;
- sprintf(buf,"/proc/%u/maps",pid);
+ sprintf(buf,"/proc/%u/maps",p->tgid);
if(!freopen(buf, "r", stdin)) return 1;
- printf("%u: %s\n", pid, get_args(pid));
- if(x_option && !q_option)
- printf("Address Kbytes RSS Anon Locked Mode Mapping\n");
- if(d_option && !q_option)
- printf("Address Kbytes Mode Offset Device Mapping\n");
+ 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;
+ unsigned long long file_offset, inode;
unsigned dev_major, dev_minor;
- sscanf(mapbuf,"%"KLF"x-%"KLF"x %31s %Lx %x:%x", &start, &end, flags, &file_offset, &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;
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+
- if(flags[3] == 'p') flags[3] = '-';
- flags[4] = '-'; // an 'R' if swap not reserved (MAP_NORESERVE, SysV ISM shared mem, etc.)
+ // an 'R' if swap not reserved (MAP_NORESERVE, SysV ISM shared mem, etc.)
+ flags[4] = '-';
flags[5] = '\0';
if(x_option){
- const char *cp = strrchr(mapbuf,'/');
- if(cp && cp[1]) cp++;
- if(!cp) cp = anon_name(pid, start, diff);
+ const char *cp = mapping_name(p, start, diff, mapbuf, 1, dev_major, dev_minor, inode);
printf(
(sizeof(KLONG)==8)
? "%016"KLF"x %7lu - - - %s %s\n"
);
}
if(d_option){
- const char *cp = strrchr(mapbuf,'/');
- if(cp && cp[1]) cp++;
- if(!cp) cp = anon_name(pid, start, diff);
+ const char *cp = mapping_name(p, start, diff, mapbuf, 1, 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",
+ ? "%016"KLF"x %7lu %s %016Lx %03x:%05x %s\n"
+ : "%08lx %7lu %s %016Lx %03x:%05x %s\n",
start,
(unsigned long)(diff>>10),
flags,
);
}
if(!x_option && !d_option){
- const char *cp = strchr(mapbuf,'/');
- if(!cp) cp = anon_name(pid, start, diff);
+ const char *cp = mapping_name(p, start, diff, mapbuf, 0, dev_major, dev_minor, inode);
printf(
(sizeof(KLONG)==8)
? "%016"KLF"x %6luK %s %s\n"
}
- if(x_option && !q_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(!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);
}
- }
- if(d_option && !q_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 && !q_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;
- unsigned u;
+ PROCTAB* PT;
+ proc_t p;
int ret = 0;
if(argc<2) usage();
if(count<1) usage(); // no processes
if(d_option && x_option) usage();
- u=0;
- while(u<count) ret |= one_proc(pidlist[u++]);
+ 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;
}