From 7b0fc19e9d28380dc9790615b93bc3653d6d686e Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Wed, 18 May 2011 10:33:44 +0200 Subject: enhanced libproc cgroup/cmdline support, exploited by top MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig --- proc/escape.c | 45 ++++++++------- proc/escape.h | 1 + proc/library.map | 2 +- proc/readproc.c | 169 ++++++++++++++++++++++++++++++++----------------------- proc/readproc.h | 14 +++-- proc/sysinfo.c | 8 +-- proc/sysinfo.h | 2 +- ps/display.c | 4 +- ps/output.c | 68 +++++++--------------- top.c | 54 +++++++----------- top.h | 21 +++---- 11 files changed, 196 insertions(+), 192 deletions(-) diff --git a/proc/escape.c b/proc/escape.c index 0eb1418..92ba4b1 100644 --- a/proc/escape.c +++ b/proc/escape.c @@ -50,13 +50,6 @@ static int escape_str_utf8(char *restrict dst, const char *restrict src, int buf my_cells++; my_bytes++; - } else if (len==1) { - /* non-multibyte */ - *(dst++) = isprint(*src) ? *src : '?'; - src++; - my_cells++; - my_bytes++; - } else if (!iswprint(wc)) { /* multibyte - no printable */ *(dst++) = '?'; @@ -98,7 +91,7 @@ static int escape_str_utf8(char *restrict dst, const char *restrict src, int buf } //fprintf(stdout, "cells: %d\n", my_cells); } - *(dst++) = '\0'; + *dst = '\0'; // fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells); @@ -114,14 +107,14 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m int my_cells = 0; int my_bytes = 0; const char codes[] = - "Z-------------------------------" - "********************************" - "********************************" - "*******************************-" - "--------------------------------" - "********************************" - "********************************" - "********************************"; + "Z..............................." + "||||||||||||||||||||||||||||||||" + "||||||||||||||||||||||||||||||||" + "|||||||||||||||||||||||||||||||." + "????????????????????????????????" + "????????????????????????????????" + "????????????????????????????????" + "????????????????????????????????"; #if (__GNU_LIBRARY__ >= 6) static int utf_init=0; @@ -131,9 +124,10 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m char *enc = nl_langinfo(CODESET); utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1; } - if (utf_init==1) + if (utf_init==1 && MB_CUR_MAX>1) { /* UTF8 locales */ return escape_str_utf8(dst, src, bufsize, maxcells); + } #endif if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale @@ -143,12 +137,12 @@ int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *m break; c = (unsigned char) *(src++); if(!c) break; - if(codes[c]=='-') c='?'; + if(codes[c]!='|') c=codes[c]; my_cells++; my_bytes++; *(dst++) = c; } - *(dst++) = '\0'; + *dst = '\0'; *maxcells -= my_cells; return my_bytes; // bytes of text, excluding the NUL @@ -214,3 +208,16 @@ int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, outbuf[end] = '\0'; return end; // bytes, not including the NUL } + +///////////////////////////////////////////////// + +// copy an already 'escaped' string, +// using the traditional escape.h calling conventions +int escaped_copy(char *restrict dst, const char *restrict src, int bufsize, int *maxroom){ + int n; + if (bufsize > *maxroom+1) bufsize = *maxroom+1; + n = snprintf(dst, bufsize, "%s", src); + if (n >= bufsize) n = bufsize-1; + *maxroom -= n; + return n; +} diff --git a/proc/escape.h b/proc/escape.h index 172960f..aa9f6d6 100644 --- a/proc/escape.h +++ b/proc/escape.h @@ -17,6 +17,7 @@ EXTERN_C_BEGIN extern int escape_strlist(char *restrict dst, const char *restrict const *restrict src, size_t n, int *cells); extern int escape_str(char *restrict dst, const char *restrict src, int bufsize, int *maxcells); extern int escape_command(char *restrict const outbuf, const proc_t *restrict const pp, int bytes, int *cells, unsigned flags); +extern int escaped_copy(char *restrict dst, const char *restrict src, int bufsize, int *maxroom); EXTERN_C_END #endif diff --git a/proc/library.map b/proc/library.map index b438849..032ada0 100644 --- a/proc/library.map +++ b/proc/library.map @@ -6,7 +6,7 @@ global: __cyg_profile_func_enter; __cyg_profile_func_exit; main; readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command; - escape_str; escape_strlist; + escape_str; escape_strlist; escaped_copy; read_cmdline; openproc; closeproc; tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan; display_version; procps_version; linux_version_code; diff --git a/proc/readproc.c b/proc/readproc.c index 10146f0..b96d0a4 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -12,6 +12,7 @@ #include "version.h" #include "readproc.h" #include "alloc.h" +#include "escape.h" #include "pwcache.h" #include "devname.h" #include "procps.h" @@ -365,7 +366,7 @@ LEAVE(0x220); } /////////////////////////////////////////////////////////////////////// -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE static void oomscore2proc(const char* S, proc_t *restrict P) { sscanf(S, "%d", &P->oom_score); @@ -527,13 +528,15 @@ static char** file2strvec(const char* directory, const char* what) { return ret; } -// warning: interface may change -int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){ + // this is the former under utilized 'read_cmdline', which has been + // generalized in support of these new libproc flags: + // PROC_EDITCGRPCVT, PROC_EDITCMDLCVT +static int read_unvectored(char *restrict const dst, unsigned sz, unsigned pid, const char *what, char sep) { char name[32]; int fd; unsigned n = 0; - dst[0] = '\0'; - snprintf(name, sizeof name, "/proc/%u/cmdline", pid); + + snprintf(name, sizeof name, "/proc/%u/%s", pid, what); fd = open(name, O_RDONLY); if(fd==-1) return 0; for(;;){ @@ -543,62 +546,85 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){ break; } n += r; - if(n==sz) break; // filled the buffer + if(n==sz) { // filled the buffer + --n; // make room for '\0' + break; + } if(r==0) break; // EOF } close(fd); if(n){ - int i; - if(n==sz) n--; - dst[n] = '\0'; - i=n; - while(i--){ - int c = dst[i]; - if(c<' ' || c>'~') dst[i]=' '; - } + int i=n; + while(i--) + if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep; } + dst[n] = '\0'; return n; } -// This routine reads /proc/#/cgroup for a single task. -// It is similar to file2strvec except we filter and concatenate -// the data into a single string represented as a single vector. -static char** fill_cgroup_cvt(const char* directory) { +static char** vectorize_this_str (const char* src) { + #define pSZ (sizeof(char*)) + char *cpy, **vec; + int adj, tot; + + tot = strlen(src) + 1; // prep for our vectors + adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1)); // calc alignment bytes + cpy = xcalloc(NULL, tot + adj + (2 * pSZ)); // get new larger buffer + snprintf(cpy, tot, "%s", src); // duplicate their string + vec = (char**)(cpy + tot + adj); // prep pointer to pointers + *vec = cpy; // point 1st vector to string + *(vec+1) = NULL; // null ptr 'list' delimit + return vec; // ==> free(*vec) to dealloc + #undef pSZ +} + + // This routine reads /proc/#/cgroup for a single task. + // It is similar to file2strvec except we filter and concatenate + // the data into a single string represented as a single vector. +static void fill_cgroup_cvt (proc_t *restrict p) { #define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) ) - char sbuf[1024], dbuf[1024]; - char *src, *dst, *grp, *eob, **ret, **q; - int align, tot, x; - - *(dst = dbuf) = '\0'; // empty destination - tot = file2str(directory, "cgroup", sbuf, sizeof(sbuf)); - if (0 < tot) { // ignore true errors - eob = sbuf + tot; - for (src = sbuf; src < eob; src++) // disappear those darn nl's - if ('\n' == *src) *src = 0; - for (src = sbuf; src < eob; src += x) { - x = 1; // loop assist - if (!*src) continue; - x = strlen((grp = src)); - if ('/' == grp[x - 1]) continue; // skip empty root cgroups -#if 0 // ( undecided on the next! ) - if (strchr(grp, ':')) ++grp; // jump past hierarchy number -#endif // ( we'll keep it for now! ) - dst += snprintf(dst, vMAX, "%s%s", (dst > dbuf) ? "," : "", grp); - } - } - if (!dbuf[0]) strncpy(dbuf, "-", sizeof(dbuf)); - tot = strlen(dbuf) + 1; // prep for our vectors - align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1)); - dst = xcalloc(NULL, tot + align + (2 * sizeof(char*))); - strncpy(dst, dbuf, tot); // propogate our handiwork - eob = dst + tot + align; // point to vectors home - q = ret = (char**)(eob); - *q++ = dst; // point 1st vector to string - *q = 0; // delimit 2nd (last) vector - return ret; // ==> free(*ret) to dealloc + char sbuf[1024], dbuf[1024]; + char *src, *dst, *grp, *eob; + int tot, x, whackable_int = sizeof(dbuf); + + *(dst = dbuf) = '\0'; // empty destination + tot = read_unvectored(sbuf, sizeof(sbuf), p->tid, "cgroup", '\0'); + for (src = sbuf, eob = sbuf + tot; src < eob; src += x) { + x = 1; // loop assist + if (!*src) continue; + x = strlen((grp = src)); + if ('/' == grp[x - 1]) continue; // skip empty root cgroups +#if 0 + grp += strspn(grp, "0123456789:"); // jump past group number +#endif + dst += snprintf(dst, vMAX, "%s", (dst > dbuf) ? "," : ""); + dst += escape_str(dst, grp, vMAX, &whackable_int); + } + p->cgroup = vectorize_this_str(dbuf[0] ? dbuf : "-"); #undef vMAX } + // This routine reads /proc/#/cmdline for the designated task, "escapes" + // the result into a single string represented as a single vector and + // guarantees the caller a valid proc_t.cmdline pointer. +static void fill_cmdline_cvt (proc_t *restrict p) { + #define uFLG ( ESC_BRACKETS | ESC_DEFUNCT ) + char sbuf[2048], dbuf[2048]; + int whackable_int = sizeof(dbuf); + + if (read_unvectored(sbuf, sizeof(sbuf), p->tid, "cmdline", ' ')) + escape_str(dbuf, sbuf, sizeof(dbuf), &whackable_int); + else + escape_command(dbuf, p, sizeof(dbuf), &whackable_int, uFLG); + p->cmdline = vectorize_this_str(dbuf); + #undef uFLG +} + +// warning: interface may change +int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid) { + return read_unvectored(dst, sz, pid, "cmdline", ' '); +} + /* These are some nice GNU C expression subscope "inline" functions. * The can be used with arbitrary types and evaluate their arguments @@ -681,31 +707,36 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons } } - if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */ - p->cmdline = file2strvec(path, "cmdline"); + if (unlikely(flags & PROC_FILLENV)) /* read /proc/#/environ */ + p->environ = file2strvec(path, "environ"); else + p->environ = NULL; + + if (flags & (PROC_FILLCOM|PROC_FILLARG)) { /* read /proc/#/cmdline */ + if (flags & PROC_EDITCMDLCVT) + fill_cmdline_cvt(p); + else + p->cmdline = file2strvec(path, "cmdline"); + } else p->cmdline = NULL; - if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */ - p->environ = file2strvec(path, "environ"); - else - p->environ = NULL; -#ifdef ZAP_SUSEONLY + if ((flags & PROC_FILLCGROUP) /* read /proc/#/cgroup, if possible */ + && linux_version_code >= LINUX_VERSION(2,6,24)) { + if (flags & PROC_EDITCGRPCVT) + fill_cgroup_cvt(p); + else + p->cgroup = file2strvec(path, "cgroup"); + } else + p->cgroup = NULL; + +#ifdef OOMEM_ENABLE if (unlikely(flags & PROC_FILLOOM)) { - if (likely( file2str(path, "oom_score", sbuf, sizeof sbuf) != -1 )) - oomscore2proc(sbuf, p); - if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 )) - oomadj2proc(sbuf, p); - } /* struct has been zeroed out before, so no worries about clearing garbage here */ + if (likely( file2str(path, "oom_score", sbuf, sizeof sbuf) != -1 )) + oomscore2proc(sbuf, p); + if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 )) + oomadj2proc(sbuf, p); + } #endif - if(linux_version_code>=LINUX_VERSION(2,6,24) && (flags & PROC_FILLCGROUP)) { - if((flags & PROC_EDITCGRPCVT)) { - p->cgroup = fill_cgroup_cvt(path); /* read /proc/#/cgroup and edit results */ - } else { - p->cgroup = file2strvec(path, "cgroup"); /* read /proc/#/cgroup */ - } - } else - p->cgroup = NULL; return p; next_proc: diff --git a/proc/readproc.h b/proc/readproc.h index c6c9bbe..b8d97bb 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -111,8 +111,9 @@ typedef struct proc_t { cmin_flt, // stat cumulative min_flt of process and child processes cmaj_flt; // stat cumulative maj_flt of process and child processes char - **environ, // (special) environment string vector (/proc/#/environ) - **cmdline; // (special) command line string vector (/proc/#/cmdline) + **environ, // (special) environment string vector (/proc/#/environ) + **cmdline, // (special) command line string vector (/proc/#/cmdline) + **cgroup; // (special) cgroup string vector (/proc/#/cgroup) char // Be compatible: Digital allows 16 and NT allows 14 ??? euser[P_G_SZ], // stat(),status effective user name @@ -140,11 +141,11 @@ typedef struct proc_t { tpgid, // stat terminal process group id exit_signal, // stat might not be SIGCHLD processor; // stat current (or most recent?) CPU -#ifdef ZAP_SUSEONLY - int oom_score, // oom_score (badness for OOM killer) - oom_adj; // oom_adj (adjustment to OOM score) +#ifdef OOMEM_ENABLE + int + oom_score, // oom_score (badness for OOM killer) + oom_adj; // oom_adj (adjustment to OOM score) #endif - char **cgroup; // cgroup current cgroup, looks like a classic filepath } proc_t; // PROCTAB: data structure holding the persistent information readproc needs @@ -252,6 +253,7 @@ extern proc_t * get_proc_stats(pid_t pid, proc_t *p); #define PROC_UID 0x4000 // user id numbers ( length needed ) #define PROC_EDITCGRPCVT 0x10000 // edit `cgroup' as single vector +#define PROC_EDITCMDLCVT 0x20000 // edit `cmdline' as single vector // it helps to give app code a few spare bits #define PROC_SPARE_1 0x01000000 diff --git a/proc/sysinfo.c b/proc/sysinfo.c index 2f26d74..952faf4 100644 --- a/proc/sysinfo.c +++ b/proc/sysinfo.c @@ -24,7 +24,7 @@ #include /* htons */ #endif -#ifndef ZAP_SUSEONLY +#ifndef OOMEM_ENABLE long smp_num_cpus; /* number of CPUs */ #endif @@ -182,7 +182,7 @@ static void old_Hertz_hack(void){ setlocale(LC_NUMERIC, savelocale); jiffies = user_j + nice_j + sys_j + other_j; seconds = (up_1 + up_2) / 2; -#ifndef ZAP_SUSEONLY +#ifndef OOMEM_ENABLE h = (unsigned)( (double)jiffies/seconds/smp_num_cpus ); #else h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() ); @@ -252,7 +252,7 @@ static int check_for_privs(void){ return !!rc; } -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE long smp_num_cpus(void) { static long _smp_num_cpus=-1; /* number of CPUs */ @@ -279,7 +279,7 @@ static void init_libproc(void) __attribute__((constructor)); static void init_libproc(void){ have_privs = check_for_privs(); init_Linux_version(); /* Must be called before we check code */ -#ifndef ZAP_SUSEONLY +#ifndef OOMEM_ENABLE // ought to count CPUs in /proc/stat instead of relying // on glibc, which foolishly tries to parse /proc/cpuinfo // diff --git a/proc/sysinfo.h b/proc/sysinfo.h index 9834477..744f280 100644 --- a/proc/sysinfo.h +++ b/proc/sysinfo.h @@ -7,7 +7,7 @@ EXTERN_C_BEGIN extern unsigned long long Hertz; /* clock tick frequency */ -#ifndef ZAP_SUSEONLY +#ifndef OOMEM_ENABLE extern long smp_num_cpus; /* number of CPUs */ #else extern long smp_num_cpus(void); /* number of CPUs */ diff --git a/ps/display.c b/ps/display.c index 3d6bbde..035a884 100644 --- a/ps/display.c +++ b/ps/display.c @@ -224,6 +224,7 @@ static unsigned task_format_needs; #define needs_for_format (proc_format_needs|task_format_needs) #define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM|PROC_FILLCGROUP) + /***** munge lists and determine openproc() flags */ static void lists_and_needs(void){ check_headers(); @@ -283,11 +284,12 @@ static void lists_and_needs(void){ } if(!unix_f_option){ proc_format_needs &= ~PROC_FILLCOM; + proc_format_needs |= PROC_EDITCMDLCVT; needs_for_sort &= ~PROC_FILLCOM; } // convert ARG to COM as a standard if(proc_format_needs & PROC_FILLARG){ - proc_format_needs |= PROC_FILLCOM; + proc_format_needs |= (PROC_FILLCOM | PROC_EDITCMDLCVT); proc_format_needs &= ~PROC_FILLARG; } if(bsd_e_option){ diff --git a/ps/output.c b/ps/output.c index e216914..6063c90 100644 --- a/ps/output.c +++ b/ps/output.c @@ -331,8 +331,11 @@ Modifications to the arguments are not shown. // FIXME: some of these may hit the guard page in forest mode -/* "command" is the same thing: long unless c */ -static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp){ +/* + * "args", "cmd", "command" are all the same: long unless c + * "comm", "ucmd", "ucomm" are all the same: short unless -f + * ( determinations are made in display.c, we just deal with results ) */ +static int pr_argcom(char *restrict const outbuf, const proc_t *restrict const pp){ char *endp = outbuf; unsigned flags; int rightward=max_rightward; @@ -342,17 +345,14 @@ static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp) endp += fh; rightward -= fh; } - if(bsd_c_option) flags = ESC_DEFUNCT; - else flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS; - endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, flags); - - if(bsd_e_option && rightward>1){ - const char **env = (const char**)pp->environ; - if(env && *env){ - *endp++ = ' '; - rightward--; - endp += escape_strlist(endp, env, OUTBUF_SIZE, &rightward); - } + if(pp->cmdline) + endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward); + else + endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT); + + if(bsd_e_option && rightward>1) { + if(pp->environ && *pp->environ) + endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward); } //return endp - outbuf; return max_rightward-rightward; @@ -361,40 +361,14 @@ static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp) static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) { int rightward = max_rightward; - if(pp->cgroup && *pp->cgroup) { - escape_str(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward); + if(pp->cgroup) { + escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward); return max_rightward-rightward; } else return pr_nop(outbuf,pp); } -/* "ucomm" is the same thing: short unless -f */ -static int pr_comm(char *restrict const outbuf, const proc_t *restrict const pp){ - char *endp = outbuf; - unsigned flags; - int rightward=max_rightward; - - if(forest_prefix){ - int fh = forest_helper(outbuf); - endp += fh; - rightward -= fh; - } - if(unix_f_option) flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS; - else flags = ESC_DEFUNCT; - endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, flags); - - if(bsd_e_option && rightward>1){ - const char **env = (const char**)pp->environ; - if(env && *env){ - *endp++ = ' '; - rightward--; - endp += escape_strlist(endp, env, OUTBUF_SIZE, &rightward); - } - } - //return endp - outbuf; - return max_rightward-rightward; -} /* Non-standard, from SunOS 5 */ static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){ char *endp = outbuf; @@ -1295,7 +1269,7 @@ static const format_struct format_array[] = { {"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT}, {"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT}, {"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|RIGHT}, -{"args", "COMMAND", pr_args, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/ +{"args", "COMMAND", pr_argcom, sr_cmd, 27, ARG, U98, PO|UNLIMITED}, /*command*/ {"atime", "TIME", pr_time, sr_nop, 8, 0, SOE, ET|RIGHT}, /*cputime*/ /* was 6 wide */ {"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/ {"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT}, @@ -1307,11 +1281,11 @@ static const format_struct format_array[] = { {"class", "CLS", pr_class, sr_sched, 3, 0, XXX, TO|LEFT}, {"cls", "CLS", pr_class, sr_sched, 3, 0, HPU, TO|RIGHT}, /*says HPUX or RT*/ {"cmaj_flt", "-", pr_nop, sr_cmaj_flt, 1, 0, LNX, AN|RIGHT}, -{"cmd", "CMD", pr_args, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/ +{"cmd", "CMD", pr_argcom, sr_cmd, 27, ARG, DEC, PO|UNLIMITED}, /*ucomm*/ {"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT}, {"cnswap", "-", pr_nop, sr_nop, 1, 0, LNX, AN|RIGHT}, -{"comm", "COMMAND", pr_comm, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/ -{"command", "COMMAND", pr_args, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/ +{"comm", "COMMAND", pr_argcom, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/ +{"command", "COMMAND", pr_argcom, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/ {"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT}, {"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/ {"cpu", "CPU", pr_nop, sr_nop, 3, 0, BSD, AN|RIGHT}, /* FIXME ... HP-UX wants this as the CPU number for SMP? */ @@ -1491,8 +1465,8 @@ static const format_struct format_array[] = { {"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT}, {"tty8", "TTY", pr_tty8, sr_tty, 8, 0, LNX, PO|LEFT}, {"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT}, -{"ucmd", "CMD", pr_comm, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/ -{"ucomm", "COMMAND", pr_comm, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/ +{"ucmd", "CMD", pr_argcom, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/ +{"ucomm", "COMMAND", pr_argcom, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/ {"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT}, {"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER}, {"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT}, diff --git a/top.c b/top.c index b7ca132..06841cb 100644 --- a/top.c +++ b/top.c @@ -40,7 +40,6 @@ #include #include "proc/devname.h" -#include "proc/escape.h" #include "proc/procps.h" #include "proc/readproc.h" #include "proc/sig.h" @@ -194,19 +193,8 @@ static int *PHash_sav = HHash_one, // alternating 'old/new' hash tables * routine may serve more than one column. */ -SCB_STRV(CGR, cgroup) -static int SCB_NAME(CMD) (const proc_t **P, const proc_t **Q) { - /* if a process doesn't have a cmdline, we'll consider it a kernel thread - -- since displayed tasks are given special treatment, we must too */ - if (Frame_cmdlin && ((*P)->cmdline || (*Q)->cmdline)) { - if (!(*Q)->cmdline) return Frame_srtflg * -1; - if (!(*P)->cmdline) return Frame_srtflg; - return Frame_srtflg * - STRSORTCMP((*Q)->cmdline[0], (*P)->cmdline[0]); - } - // this part also handles the compare if both are kernel threads - return Frame_srtflg * STRSORTCMP((*Q)->cmd, (*P)->cmd); -} +SCB_STRV(CGR, 1, cgroup, cgroup[0]) +SCB_STRV(CMD, Frame_cmdlin, cmdline, cmd) SCB_NUM1(COD, trs) SCB_NUMx(CPN, processor) SCB_NUM1(CPU, pcpu) @@ -218,7 +206,7 @@ SCB_NUM1(FL2, min_flt) SCB_NUMx(GID, egid) SCB_STRS(GRP, egroup) SCB_NUMx(NCE, nice) -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE SCB_NUM1(OOA, oom_adj) SCB_NUM1(OOM, oom_score) #endif @@ -1169,7 +1157,7 @@ static inline int user_matched (WIN_t *q, const proc_t *p) { #define L_statm PROC_FILLMEM #define L_status PROC_FILLSTATUS #define L_CGROUP PROC_EDITCGRPCVT | PROC_FILLCGROUP -#define L_CMDLINE PROC_FILLARG +#define L_CMDLINE PROC_EDITCMDLCVT | PROC_FILLARG #define L_EUSER PROC_FILLUSR #define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR #define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP @@ -1242,7 +1230,7 @@ static FLD_t Fieldstab[] = { #endif // next entry's like P_CMD, and '.head' must be the same length -- they share varcolsz { "CGROUPS ", NULL, -1, -1, SF(CGR), L_CGROUP, "Control Groups" } -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE #define L_oom PROC_FILLOOM ,{ "Adj ", "%3d ", -1, -1, SF(OOA), L_oom, "oom_adjustment (2^X)" } ,{ " Badness ", "%8d ", -1, -1, SF(OOM), L_oom, "oom_score (badness)" } @@ -1441,7 +1429,10 @@ static void calibrate_fields (void) { // prepare to even out column header lengths... if (hdrmax + w->hdrcaplen < (x = strlen(w->columnhdr))) hdrmax = x - w->hdrcaplen; #endif - + // we must also accommodate an out of view sort field... + f = w->rc.sortindx; + Frames_libflags |= Fieldstab[f].lflg; + if (P_CMD == f && CHKw(w, Show_CMDLIN)) Frames_libflags |= L_CMDLINE; } // end: VIZISw(w) if (Rc.mode_altscr) w = w->next; } while (w != Curwin); @@ -2977,9 +2968,10 @@ static void do_key (int ch) { break; } - if (i < MAXTBL(key_tab)) break; - show_msg("\aUnknown command - try 'h' for help"); - return; + if (!(i < MAXTBL(key_tab))) { + show_msg("\aUnknown command - try 'h' for help"); + return; + } }; /* The following assignment will force a rebuild of all column headers and @@ -3022,7 +3014,7 @@ static void summaryhlp (CPU_t *cpu, const char *pfx) { s_frme = cpu->s - cpu->s_sav; n_frme = cpu->n - cpu->n_sav; i_frme = TRIMz(cpu->i - cpu->i_sav); - if ((u_frme == 0) && (i_frme == 0)) i_frme = 100.0; + if ((u_frme == 0) && (i_frme == 0)) i_frme = 100; w_frme = cpu->w - cpu->w_sav; x_frme = cpu->x - cpu->x_sav; y_frme = cpu->y - cpu->y_sav; @@ -3173,17 +3165,11 @@ static void task_show (const WIN_t *q, const proc_t *p) { #endif case P_CGR: // our kernel may not support cgroups - makeVAR(p->cgroup ? p->cgroup[0] : "n/a"); + makeVAR(p->cgroup ? *p->cgroup : "n/a"); break; case P_CMD: - { char tmp[SCREENMAX]; - unsigned flags; - int whackable_int = q->varcolsz; - if (CHKw(q, Show_CMDLIN)) flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS; - else flags = ESC_DEFUNCT; - escape_command(tmp, p, sizeof(tmp), &whackable_int, flags); - makeVAR(tmp); - } + if (CHKw(q, Show_CMDLIN)) makeVAR(*p->cmdline) + else makeVAR(p->cmd); break; case P_COD: makeCOL(scale_num(pages2K(p->trs), w, s)); @@ -3229,7 +3215,7 @@ static void task_show (const WIN_t *q, const proc_t *p) { case P_NCE: makeCOL((int)p->nice); break; -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE case P_OOA: makeCOL((int)p->oom_adj); break; @@ -3311,9 +3297,9 @@ static void task_show (const WIN_t *q, const proc_t *p) { case P_WCH: if (No_ksyms) { #ifdef CASEUP_HEXES - makeVAR(fmtmk("%010lX", (unsigned long)(unsigned int)p->wchan)) + makeVAR(fmtmk("%08" KLF "X", p->wchan)) #else - makeVAR(fmtmk("%010lx", (unsigned long)(unsigned int)p->wchan)) + makeVAR(fmtmk("%08" KLF "x", p->wchan)) #endif } else makeVAR(lookup_wchan(p->wchan, p->tid)) diff --git a/top.h b/top.h index 580266d..804eec4 100644 --- a/top.h +++ b/top.h @@ -28,6 +28,7 @@ //#define FIELD_CURSOR /* cursor follows selection w/ fields mgmt */ //#define OFF_HST_HASH /* use BOTH qsort+bsrch vs. hashing scheme */ //#define OFF_STDIOLBF /* disable our own stdout _IOFBF override */ +//#define OOMEM_ENABLE /* enable the SuSE out-of-memory additions * //#define PRETEND2_5_X /* pretend we're linux 2.5.x (for IO-wait) */ //#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */ //#define PRETENDNOCAP /* use a terminal without essential caps */ @@ -38,7 +39,6 @@ //#define TERMIOS_ONLY /* just limp along with native input only */ //#define TTYGETENVYES /* environ vars can override tty col/row */ //#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */ -//#define ZAP_SUSEONLY /* enable the SuSE specific modifications */ /*###### Notes, etc. ###################################################*/ @@ -65,7 +65,7 @@ #define STRSORTCMP strcmp #endif -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE /* FIXME: perhaps making this a function in the suse version of sysinfo.c was a prelude to hotpluggable updates -- unfortunately, the return value is invariant as currently implemented! */ @@ -139,7 +139,7 @@ enum pflag { P_MEM, P_VRT, P_SWP, P_RES, P_COD, P_DAT, P_SHR, P_FL1, P_FL2, P_DRT, P_STA, P_CMD, P_WCH, P_FLG, P_CGR, -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE P_OOA, P_OOM, #endif #ifdef USE_X_COLHDR @@ -375,11 +375,12 @@ typedef struct WIN_t { #define SCB_STRS(f,s) \ static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \ return Frame_srtflg * STRSORTCMP((*Q)->s, (*P)->s); } -#define SCB_STRV(f,s) \ +#define SCB_STRV(f,b,v,s) \ static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \ - if (!(*P)->s || !(*Q)->s) \ - return SORT_eq; \ - return Frame_srtflg * STRSORTCMP((*Q)->s[0], (*P)->s[0]); } + if (b) { \ + if (!(*P)->v || !(*Q)->v) return SORT_eq; \ + return Frame_srtflg * STRSORTCMP((*Q)->v[0], (*P)->v[0]); } \ + return Frame_srtflg * STRSORTCMP((*Q)->s, (*P)->s); } /* * The following two macros are used to 'inline' those portions of the @@ -532,7 +533,7 @@ typedef struct WIN_t { " 'd' or toggles display, 's' sets sort. Use 'q' or to end! " \ "" -#ifdef ZAP_SUSEONLY +#ifdef OOMEM_ENABLE /* w/ 2 extra lines, no room for additional text on 24x80 terminal */ #define FIELDS_notes NULL #else @@ -634,8 +635,8 @@ typedef struct WIN_t { #if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH) # error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH' #endif -#if defined(PRETEND4CPUS) && defined (ZAP_SUSEONLY) -# error 'PRETEND4CPUS' conflicts with 'ZAP_SUSEONLY' +#if defined(PRETEND4CPUS) && defined (OOMEM_ENABLE) +# error 'PRETEND4CPUS' conflicts with 'OOMEM_ENABLE' #endif -- cgit v1.2.1