diff --git a/Makefile b/Makefile index df5001e2..c73179d5 100644 --- a/Makefile +++ b/Makefile @@ -61,12 +61,13 @@ MANFILES := $(man1)uptime.1 $(man1)tload.1 $(man1)free.1 $(man1)w.1 \ TARFILES := AUTHORS BUGS NEWS README TODO COPYING COPYING.LIB \ Makefile procps.lsm procps.spec v t README.top \ - minimal.c $(notdir $(MANFILES)) \ + minimal.c $(notdir $(MANFILES)) dummy.c \ uptime.c tload.c free.c w.c top.c vmstat.c watch.c skill.c \ sysctl.c pgrep.c top.h pmap.c slabtop.c # Stuff (tests, temporary hacks, etc.) left out of the standard tarball -_TARFILES := +# plus the top-level Makefile to make it work stand-alone. +_TARFILES := Makefile CURSES := -I/usr/include/ncurses -lncurses @@ -94,6 +95,27 @@ PKG_LDFLAGS := -Wl,-warn-common LDFLAGS := ALL_LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS) +############ Add some extra flags if gcc allows + +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),tar) +ifneq ($(MAKECMDGOALS),extratar) + +# Unlike the kernel one, this check_gcc goes all the way to +# producing an executable. There might be a -m64 that works +# until you go looking for a 64-bit curses library. +check_gcc = $(shell if $(CC) $(ALL_CFLAGS) dummy.c $(ALL_LDFLAGS) $(1) -o /dev/null $(CURSES) > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) + +ALL_CFLAGS += $(call check_gcc,-Wdeclaration-after-statement,) +ALL_CFLAGS += $(call check_gcc,-Wpadded,) + +# Be 64-bit if at all possible. +ALL_CFLAGS += $(call check_gcc,-m64,) + +endif +endif +endif + ############ misc. # free.c pmap.c sysctl.c uptime.c vmstat.c watch.c pgrep.c skill.c tload.c top.c w.c @@ -179,13 +201,13 @@ w.o: w.c ############ prog.o --> prog pmap w uptime tload free sysctl vmstat utmp pgrep skill: % : %.o $(LIBPROC) - $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ + $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ slabtop top: % : %.o $(LIBPROC) - $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CURSES) + $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ $(CURSES) watch: % : %.o - $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $^ $(CURSES) + $(CC) $(ALL_CFLAGS) $^ $(ALL_LDFLAGS) -o $@ $(CURSES) ############ progX --> progY diff --git a/dummy.c b/dummy.c new file mode 100644 index 00000000..95e78247 --- /dev/null +++ b/dummy.c @@ -0,0 +1,31 @@ +// This is to test the compiler. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Foul POS defines all sorts of stuff... +#include +#undef tab + +#include +#include +#include +#include + +int main(int argc, char *argv[]){ + (void)argc; + (void)argv; + return 0; +} diff --git a/pmap.c b/pmap.c index a2075ac1..003db4fc 100644 --- a/pmap.c +++ b/pmap.c @@ -17,8 +17,13 @@ #include #include #include + +#include +#include + #include "proc/readproc.h" #include "proc/version.h" +#include "proc/escape.h" static void usage(void) NORETURN; static void usage(void){ @@ -40,81 +45,111 @@ static int d_option; static int q_option; -static const char *get_args(unsigned pid){ - static char cmdbuf[64]; - char buf[32]; - int fd; - ssize_t count; +static unsigned shm_minor = ~0u; - 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); +static void discover_shm_minor(void){ + void *addr; + int shmid; + char mapbuf[256]; - 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); + if(!freopen("/proc/self/maps", "r", stdin)) return; - return "[]"; // as good as anything + // 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; + } + } + + 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; @@ -126,19 +161,18 @@ static int one_proc(unsigned pid){ 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" @@ -150,13 +184,11 @@ static int one_proc(unsigned pid){ ); } 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, @@ -166,8 +198,7 @@ static int one_proc(unsigned pid){ ); } 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" @@ -181,32 +212,34 @@ static int one_proc(unsigned pid){ } - 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; @@ -216,7 +249,8 @@ static int one_proc(unsigned pid){ 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(); @@ -276,8 +310,17 @@ int main(int argc, char *argv[]){ if(count<1) usage(); // no processes if(d_option && x_option) usage(); - u=0; - while(u