enhanced libproc cgroup/cmdline support, exploited by top

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 <jgorig@redhat.com>
This commit is contained in:
Jim Warner 2011-05-18 10:33:44 +02:00 committed by Jan Görig
parent 8621387c77
commit 7b0fc19e9d
11 changed files with 197 additions and 193 deletions

View File

@ -50,13 +50,6 @@ static int escape_str_utf8(char *restrict dst, const char *restrict src, int buf
my_cells++; my_cells++;
my_bytes++; my_bytes++;
} else if (len==1) {
/* non-multibyte */
*(dst++) = isprint(*src) ? *src : '?';
src++;
my_cells++;
my_bytes++;
} else if (!iswprint(wc)) { } else if (!iswprint(wc)) {
/* multibyte - no printable */ /* multibyte - no printable */
*(dst++) = '?'; *(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); //fprintf(stdout, "cells: %d\n", my_cells);
} }
*(dst++) = '\0'; *dst = '\0';
// fprintf(stderr, "maxcells: %d, my_cells; %d\n", *maxcells, my_cells); // 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_cells = 0;
int my_bytes = 0; int my_bytes = 0;
const char codes[] = const char codes[] =
"Z-------------------------------" "Z..............................."
"********************************" "||||||||||||||||||||||||||||||||"
"********************************" "||||||||||||||||||||||||||||||||"
"*******************************-" "|||||||||||||||||||||||||||||||."
"--------------------------------" "????????????????????????????????"
"********************************" "????????????????????????????????"
"********************************" "????????????????????????????????"
"********************************"; "????????????????????????????????";
#if (__GNU_LIBRARY__ >= 6) #if (__GNU_LIBRARY__ >= 6)
static int utf_init=0; 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); char *enc = nl_langinfo(CODESET);
utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1; utf_init = enc && strcasecmp(enc, "UTF-8")==0 ? 1 : -1;
} }
if (utf_init==1) if (utf_init==1 && MB_CUR_MAX>1) {
/* UTF8 locales */ /* UTF8 locales */
return escape_str_utf8(dst, src, bufsize, maxcells); return escape_str_utf8(dst, src, bufsize, maxcells);
}
#endif #endif
if(bufsize > *maxcells+1) bufsize=*maxcells+1; // FIXME: assumes 8-bit locale 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; break;
c = (unsigned char) *(src++); c = (unsigned char) *(src++);
if(!c) break; if(!c) break;
if(codes[c]=='-') c='?'; if(codes[c]!='|') c=codes[c];
my_cells++; my_cells++;
my_bytes++; my_bytes++;
*(dst++) = c; *(dst++) = c;
} }
*(dst++) = '\0'; *dst = '\0';
*maxcells -= my_cells; *maxcells -= my_cells;
return my_bytes; // bytes of text, excluding the NUL 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'; outbuf[end] = '\0';
return end; // bytes, not including the NUL 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;
}

View File

@ -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_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_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 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 EXTERN_C_END
#endif #endif

View File

@ -6,7 +6,7 @@ global:
__cyg_profile_func_enter; __cyg_profile_func_exit; main; __cyg_profile_func_enter; __cyg_profile_func_exit; main;
readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command; readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command;
escape_str; escape_strlist; escape_str; escape_strlist; escaped_copy; read_cmdline;
openproc; closeproc; openproc; closeproc;
tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan; tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan;
display_version; procps_version; linux_version_code; display_version; procps_version; linux_version_code;

View File

@ -12,6 +12,7 @@
#include "version.h" #include "version.h"
#include "readproc.h" #include "readproc.h"
#include "alloc.h" #include "alloc.h"
#include "escape.h"
#include "pwcache.h" #include "pwcache.h"
#include "devname.h" #include "devname.h"
#include "procps.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) static void oomscore2proc(const char* S, proc_t *restrict P)
{ {
sscanf(S, "%d", &P->oom_score); sscanf(S, "%d", &P->oom_score);
@ -527,13 +528,15 @@ static char** file2strvec(const char* directory, const char* what) {
return ret; return ret;
} }
// warning: interface may change // this is the former under utilized 'read_cmdline', which has been
int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){ // 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]; char name[32];
int fd; int fd;
unsigned n = 0; 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); fd = open(name, O_RDONLY);
if(fd==-1) return 0; if(fd==-1) return 0;
for(;;){ for(;;){
@ -543,62 +546,85 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){
break; break;
} }
n += r; 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 if(r==0) break; // EOF
} }
close(fd); close(fd);
if(n){ if(n){
int i; int i=n;
if(n==sz) n--; while(i--)
dst[n] = '\0'; if(dst[i]=='\n' || dst[i]=='\0') dst[i]=sep;
i=n;
while(i--){
int c = dst[i];
if(c<' ' || c>'~') dst[i]=' ';
}
} }
dst[n] = '\0';
return n; return n;
} }
// This routine reads /proc/#/cgroup for a single task. static char** vectorize_this_str (const char* src) {
// It is similar to file2strvec except we filter and concatenate #define pSZ (sizeof(char*))
// the data into a single string represented as a single vector. char *cpy, **vec;
static char** fill_cgroup_cvt(const char* directory) { int adj, tot;
#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 = strlen(src) + 1; // prep for our vectors
tot = file2str(directory, "cgroup", sbuf, sizeof(sbuf)); adj = (pSZ-1) - ((tot + pSZ-1) & (pSZ-1)); // calc alignment bytes
if (0 < tot) { // ignore true errors cpy = xcalloc(NULL, tot + adj + (2 * pSZ)); // get new larger buffer
eob = sbuf + tot; snprintf(cpy, tot, "%s", src); // duplicate their string
for (src = sbuf; src < eob; src++) // disappear those darn nl's vec = (char**)(cpy + tot + adj); // prep pointer to pointers
if ('\n' == *src) *src = 0; *vec = cpy; // point 1st vector to string
for (src = sbuf; src < eob; src += x) { *(vec+1) = NULL; // null ptr 'list' delimit
x = 1; // loop assist return vec; // ==> free(*vec) to dealloc
if (!*src) continue; #undef pSZ
x = strlen((grp = src)); }
if ('/' == grp[x - 1]) continue; // skip empty root cgroups
#if 0 // ( undecided on the next! ) // This routine reads /proc/#/cgroup for a single task.
if (strchr(grp, ':')) ++grp; // jump past hierarchy number // It is similar to file2strvec except we filter and concatenate
#endif // ( we'll keep it for now! ) // the data into a single string represented as a single vector.
dst += snprintf(dst, vMAX, "%s%s", (dst > dbuf) ? "," : "", grp); static void fill_cgroup_cvt (proc_t *restrict p) {
} #define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) )
} char sbuf[1024], dbuf[1024];
if (!dbuf[0]) strncpy(dbuf, "-", sizeof(dbuf)); char *src, *dst, *grp, *eob;
tot = strlen(dbuf) + 1; // prep for our vectors int tot, x, whackable_int = sizeof(dbuf);
align = (sizeof(char*)-1) - ((tot + sizeof(char*)-1) & (sizeof(char*)-1));
dst = xcalloc(NULL, tot + align + (2 * sizeof(char*))); *(dst = dbuf) = '\0'; // empty destination
strncpy(dst, dbuf, tot); // propogate our handiwork tot = read_unvectored(sbuf, sizeof(sbuf), p->tid, "cgroup", '\0');
eob = dst + tot + align; // point to vectors home for (src = sbuf, eob = sbuf + tot; src < eob; src += x) {
q = ret = (char**)(eob); x = 1; // loop assist
*q++ = dst; // point 1st vector to string if (!*src) continue;
*q = 0; // delimit 2nd (last) vector x = strlen((grp = src));
return ret; // ==> free(*ret) to dealloc 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 #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. /* These are some nice GNU C expression subscope "inline" functions.
* The can be used with arbitrary types and evaluate their arguments * 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 */ if (unlikely(flags & PROC_FILLENV)) /* read /proc/#/environ */
p->cmdline = file2strvec(path, "cmdline"); p->environ = file2strvec(path, "environ");
else
p->cmdline = NULL;
if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */
p->environ = file2strvec(path, "environ");
else else
p->environ = NULL; p->environ = NULL;
#ifdef ZAP_SUSEONLY
if (unlikely(flags & PROC_FILLOOM)) { if (flags & (PROC_FILLCOM|PROC_FILLARG)) { /* read /proc/#/cmdline */
if (likely( file2str(path, "oom_score", sbuf, sizeof sbuf) != -1 )) if (flags & PROC_EDITCMDLCVT)
oomscore2proc(sbuf, p); fill_cmdline_cvt(p);
if (likely( file2str(path, "oom_adj", sbuf, sizeof sbuf) != -1 )) else
oomadj2proc(sbuf, p); p->cmdline = file2strvec(path, "cmdline");
} /* struct has been zeroed out before, so no worries about clearing garbage here */
#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 } else
p->cgroup = NULL; p->cmdline = NULL;
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);
}
#endif
return p; return p;
next_proc: next_proc:

View File

@ -111,8 +111,9 @@ typedef struct proc_t {
cmin_flt, // stat cumulative min_flt of process and child processes cmin_flt, // stat cumulative min_flt of process and child processes
cmaj_flt; // stat cumulative maj_flt of process and child processes cmaj_flt; // stat cumulative maj_flt of process and child processes
char char
**environ, // (special) environment string vector (/proc/#/environ) **environ, // (special) environment string vector (/proc/#/environ)
**cmdline; // (special) command line string vector (/proc/#/cmdline) **cmdline, // (special) command line string vector (/proc/#/cmdline)
**cgroup; // (special) cgroup string vector (/proc/#/cgroup)
char char
// Be compatible: Digital allows 16 and NT allows 14 ??? // Be compatible: Digital allows 16 and NT allows 14 ???
euser[P_G_SZ], // stat(),status effective user name euser[P_G_SZ], // stat(),status effective user name
@ -140,11 +141,11 @@ typedef struct proc_t {
tpgid, // stat terminal process group id tpgid, // stat terminal process group id
exit_signal, // stat might not be SIGCHLD exit_signal, // stat might not be SIGCHLD
processor; // stat current (or most recent?) CPU processor; // stat current (or most recent?) CPU
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
int oom_score, // oom_score (badness for OOM killer) int
oom_adj; // oom_adj (adjustment to OOM score) oom_score, // oom_score (badness for OOM killer)
oom_adj; // oom_adj (adjustment to OOM score)
#endif #endif
char **cgroup; // cgroup current cgroup, looks like a classic filepath
} proc_t; } proc_t;
// PROCTAB: data structure holding the persistent information readproc needs // 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_UID 0x4000 // user id numbers ( length needed )
#define PROC_EDITCGRPCVT 0x10000 // edit `cgroup' as single vector #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 // it helps to give app code a few spare bits
#define PROC_SPARE_1 0x01000000 #define PROC_SPARE_1 0x01000000

View File

@ -24,7 +24,7 @@
#include <netinet/in.h> /* htons */ #include <netinet/in.h> /* htons */
#endif #endif
#ifndef ZAP_SUSEONLY #ifndef OOMEM_ENABLE
long smp_num_cpus; /* number of CPUs */ long smp_num_cpus; /* number of CPUs */
#endif #endif
@ -182,7 +182,7 @@ static void old_Hertz_hack(void){
setlocale(LC_NUMERIC, savelocale); setlocale(LC_NUMERIC, savelocale);
jiffies = user_j + nice_j + sys_j + other_j; jiffies = user_j + nice_j + sys_j + other_j;
seconds = (up_1 + up_2) / 2; seconds = (up_1 + up_2) / 2;
#ifndef ZAP_SUSEONLY #ifndef OOMEM_ENABLE
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus ); h = (unsigned)( (double)jiffies/seconds/smp_num_cpus );
#else #else
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() ); h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() );
@ -252,7 +252,7 @@ static int check_for_privs(void){
return !!rc; return !!rc;
} }
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
long smp_num_cpus(void) long smp_num_cpus(void)
{ {
static long _smp_num_cpus=-1; /* number of CPUs */ 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){ static void init_libproc(void){
have_privs = check_for_privs(); have_privs = check_for_privs();
init_Linux_version(); /* Must be called before we check code */ 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 // ought to count CPUs in /proc/stat instead of relying
// on glibc, which foolishly tries to parse /proc/cpuinfo // on glibc, which foolishly tries to parse /proc/cpuinfo
// //

View File

@ -7,7 +7,7 @@
EXTERN_C_BEGIN EXTERN_C_BEGIN
extern unsigned long long Hertz; /* clock tick frequency */ extern unsigned long long Hertz; /* clock tick frequency */
#ifndef ZAP_SUSEONLY #ifndef OOMEM_ENABLE
extern long smp_num_cpus; /* number of CPUs */ extern long smp_num_cpus; /* number of CPUs */
#else #else
extern long smp_num_cpus(void); /* number of CPUs */ extern long smp_num_cpus(void); /* number of CPUs */

View File

@ -224,6 +224,7 @@ static unsigned task_format_needs;
#define needs_for_format (proc_format_needs|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) #define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM|PROC_FILLCGROUP)
/***** munge lists and determine openproc() flags */ /***** munge lists and determine openproc() flags */
static void lists_and_needs(void){ static void lists_and_needs(void){
check_headers(); check_headers();
@ -283,11 +284,12 @@ static void lists_and_needs(void){
} }
if(!unix_f_option){ if(!unix_f_option){
proc_format_needs &= ~PROC_FILLCOM; proc_format_needs &= ~PROC_FILLCOM;
proc_format_needs |= PROC_EDITCMDLCVT;
needs_for_sort &= ~PROC_FILLCOM; needs_for_sort &= ~PROC_FILLCOM;
} }
// convert ARG to COM as a standard // convert ARG to COM as a standard
if(proc_format_needs & PROC_FILLARG){ if(proc_format_needs & PROC_FILLARG){
proc_format_needs |= PROC_FILLCOM; proc_format_needs |= (PROC_FILLCOM | PROC_EDITCMDLCVT);
proc_format_needs &= ~PROC_FILLARG; proc_format_needs &= ~PROC_FILLARG;
} }
if(bsd_e_option){ if(bsd_e_option){

View File

@ -331,8 +331,11 @@ Modifications to the arguments are not shown.
// FIXME: some of these may hit the guard page in forest mode // 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; char *endp = outbuf;
unsigned flags; unsigned flags;
int rightward=max_rightward; int rightward=max_rightward;
@ -342,17 +345,14 @@ static int pr_args(char *restrict const outbuf, const proc_t *restrict const pp)
endp += fh; endp += fh;
rightward -= fh; rightward -= fh;
} }
if(bsd_c_option) flags = ESC_DEFUNCT; if(pp->cmdline)
else flags = ESC_DEFUNCT | ESC_BRACKETS | ESC_ARGS; endp += escaped_copy(endp, *pp->cmdline, OUTBUF_SIZE, &rightward);
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, flags); else
endp += escape_command(endp, pp, OUTBUF_SIZE, &rightward, ESC_DEFUNCT);
if(bsd_e_option && rightward>1){ if(bsd_e_option && rightward>1) {
const char **env = (const char**)pp->environ; if(pp->environ && *pp->environ)
if(env && *env){ endp += escape_strlist(endp, pp->environ, OUTBUF_SIZE, &rightward);
*endp++ = ' ';
rightward--;
endp += escape_strlist(endp, env, OUTBUF_SIZE, &rightward);
}
} }
//return endp - outbuf; //return endp - outbuf;
return max_rightward-rightward; 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) { static int pr_cgroup(char *restrict const outbuf,const proc_t *restrict const pp) {
int rightward = max_rightward; int rightward = max_rightward;
if(pp->cgroup && *pp->cgroup) { if(pp->cgroup) {
escape_str(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward); escaped_copy(outbuf, *pp->cgroup, OUTBUF_SIZE, &rightward);
return max_rightward-rightward; return max_rightward-rightward;
} }
else else
return pr_nop(outbuf,pp); 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 */ /* Non-standard, from SunOS 5 */
static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){ static int pr_fname(char *restrict const outbuf, const proc_t *restrict const pp){
char *endp = outbuf; 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}, {"addr_1", "ADDR", pr_nop, sr_nop, 1, 0, LNX, AN|LEFT},
{"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT}, {"alarm", "ALARM", pr_alarm, sr_alarm, 5, 0, LNX, AN|RIGHT},
{"argc", "ARGC", pr_nop, sr_nop, 4, 0, LNX, PO|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 */ {"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*/ {"blocked", "BLOCKED", pr_sigmask, sr_nop, 9, 0, BSD, TO|SIGNAL}, /*sigmask*/
{"bnd", "BND", pr_nop, sr_nop, 1, 0, AIX, TO|RIGHT}, {"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}, {"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*/ {"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}, {"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}, {"cmin_flt", "-", pr_nop, sr_cmin_flt, 1, 0, LNX, AN|RIGHT},
{"cnswap", "-", pr_nop, sr_nop, 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*/ {"comm", "COMMAND", pr_argcom, sr_cmd, 15, COM, U98, PO|UNLIMITED}, /*ucomm*/
{"command", "COMMAND", pr_args, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/ {"command", "COMMAND", pr_argcom, sr_cmd, 27, ARG, XXX, PO|UNLIMITED}, /*args*/
{"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT}, {"context", "CONTEXT", pr_context, sr_nop, 31, 0, LNX, ET|LEFT},
{"cp", "CP", pr_cp, sr_pcpu, 3, 0, DEC, ET|RIGHT}, /*cpu*/ {"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? */ {"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}, {"tty4", "TTY", pr_tty4, sr_tty, 4, 0, LNX, PO|LEFT},
{"tty8", "TTY", pr_tty8, sr_tty, 8, 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}, {"u_procp", "UPROCP", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT},
{"ucmd", "CMD", pr_comm, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/ {"ucmd", "CMD", pr_argcom, sr_cmd, 15, COM, DEC, PO|UNLIMITED}, /*ucomm*/
{"ucomm", "COMMAND", pr_comm, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/ {"ucomm", "COMMAND", pr_argcom, sr_cmd, 15, COM, XXX, PO|UNLIMITED}, /*comm*/
{"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT}, {"uid", "UID", pr_euid, sr_euid, 5, 0, XXX, ET|RIGHT},
{"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER}, {"uid_hack", "UID", pr_euser, sr_euser, 8, USR, XXX, ET|USER},
{"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT}, {"umask", "UMASK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT},

54
top.c
View File

@ -40,7 +40,6 @@
#include <values.h> #include <values.h>
#include "proc/devname.h" #include "proc/devname.h"
#include "proc/escape.h"
#include "proc/procps.h" #include "proc/procps.h"
#include "proc/readproc.h" #include "proc/readproc.h"
#include "proc/sig.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. * routine may serve more than one column.
*/ */
SCB_STRV(CGR, cgroup) SCB_STRV(CGR, 1, cgroup, cgroup[0])
static int SCB_NAME(CMD) (const proc_t **P, const proc_t **Q) { SCB_STRV(CMD, Frame_cmdlin, cmdline, cmd)
/* 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_NUM1(COD, trs) SCB_NUM1(COD, trs)
SCB_NUMx(CPN, processor) SCB_NUMx(CPN, processor)
SCB_NUM1(CPU, pcpu) SCB_NUM1(CPU, pcpu)
@ -218,7 +206,7 @@ SCB_NUM1(FL2, min_flt)
SCB_NUMx(GID, egid) SCB_NUMx(GID, egid)
SCB_STRS(GRP, egroup) SCB_STRS(GRP, egroup)
SCB_NUMx(NCE, nice) SCB_NUMx(NCE, nice)
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
SCB_NUM1(OOA, oom_adj) SCB_NUM1(OOA, oom_adj)
SCB_NUM1(OOM, oom_score) SCB_NUM1(OOM, oom_score)
#endif #endif
@ -1169,7 +1157,7 @@ static inline int user_matched (WIN_t *q, const proc_t *p) {
#define L_statm PROC_FILLMEM #define L_statm PROC_FILLMEM
#define L_status PROC_FILLSTATUS #define L_status PROC_FILLSTATUS
#define L_CGROUP PROC_EDITCGRPCVT | PROC_FILLCGROUP #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_EUSER PROC_FILLUSR
#define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR #define L_OUSER PROC_FILLSTATUS | PROC_FILLUSR
#define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP #define L_EGROUP PROC_FILLSTATUS | PROC_FILLGRP
@ -1242,7 +1230,7 @@ static FLD_t Fieldstab[] = {
#endif #endif
// next entry's like P_CMD, and '.head' must be the same length -- they share varcolsz // 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" } { "CGROUPS ", NULL, -1, -1, SF(CGR), L_CGROUP, "Control Groups" }
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
#define L_oom PROC_FILLOOM #define L_oom PROC_FILLOOM
,{ "Adj ", "%3d ", -1, -1, SF(OOA), L_oom, "oom_adjustment (2^X)" } ,{ "Adj ", "%3d ", -1, -1, SF(OOA), L_oom, "oom_adjustment (2^X)" }
,{ " Badness ", "%8d ", -1, -1, SF(OOM), L_oom, "oom_score (badness)" } ,{ " 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... // prepare to even out column header lengths...
if (hdrmax + w->hdrcaplen < (x = strlen(w->columnhdr))) hdrmax = x - w->hdrcaplen; if (hdrmax + w->hdrcaplen < (x = strlen(w->columnhdr))) hdrmax = x - w->hdrcaplen;
#endif #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) } // end: VIZISw(w)
if (Rc.mode_altscr) w = w->next; if (Rc.mode_altscr) w = w->next;
} while (w != Curwin); } while (w != Curwin);
@ -2977,9 +2968,10 @@ static void do_key (int ch) {
break; break;
} }
if (i < MAXTBL(key_tab)) break; if (!(i < MAXTBL(key_tab))) {
show_msg("\aUnknown command - try 'h' for help"); show_msg("\aUnknown command - try 'h' for help");
return; return;
}
}; };
/* The following assignment will force a rebuild of all column headers and /* 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; s_frme = cpu->s - cpu->s_sav;
n_frme = cpu->n - cpu->n_sav; n_frme = cpu->n - cpu->n_sav;
i_frme = TRIMz(cpu->i - cpu->i_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; w_frme = cpu->w - cpu->w_sav;
x_frme = cpu->x - cpu->x_sav; x_frme = cpu->x - cpu->x_sav;
y_frme = cpu->y - cpu->y_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 #endif
case P_CGR: case P_CGR:
// our kernel may not support cgroups // our kernel may not support cgroups
makeVAR(p->cgroup ? p->cgroup[0] : "n/a"); makeVAR(p->cgroup ? *p->cgroup : "n/a");
break; break;
case P_CMD: case P_CMD:
{ char tmp[SCREENMAX]; if (CHKw(q, Show_CMDLIN)) makeVAR(*p->cmdline)
unsigned flags; else makeVAR(p->cmd);
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);
}
break; break;
case P_COD: case P_COD:
makeCOL(scale_num(pages2K(p->trs), w, s)); 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: case P_NCE:
makeCOL((int)p->nice); makeCOL((int)p->nice);
break; break;
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
case P_OOA: case P_OOA:
makeCOL((int)p->oom_adj); makeCOL((int)p->oom_adj);
break; break;
@ -3311,9 +3297,9 @@ static void task_show (const WIN_t *q, const proc_t *p) {
case P_WCH: case P_WCH:
if (No_ksyms) { if (No_ksyms) {
#ifdef CASEUP_HEXES #ifdef CASEUP_HEXES
makeVAR(fmtmk("%010lX", (unsigned long)(unsigned int)p->wchan)) makeVAR(fmtmk("%08" KLF "X", p->wchan))
#else #else
makeVAR(fmtmk("%010lx", (unsigned long)(unsigned int)p->wchan)) makeVAR(fmtmk("%08" KLF "x", p->wchan))
#endif #endif
} else } else
makeVAR(lookup_wchan(p->wchan, p->tid)) makeVAR(lookup_wchan(p->wchan, p->tid))

21
top.h
View File

@ -28,6 +28,7 @@
//#define FIELD_CURSOR /* cursor follows selection w/ fields mgmt */ //#define FIELD_CURSOR /* cursor follows selection w/ fields mgmt */
//#define OFF_HST_HASH /* use BOTH qsort+bsrch vs. hashing scheme */ //#define OFF_HST_HASH /* use BOTH qsort+bsrch vs. hashing scheme */
//#define OFF_STDIOLBF /* disable our own stdout _IOFBF override */ //#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 PRETEND2_5_X /* pretend we're linux 2.5.x (for IO-wait) */
//#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */ //#define PRETEND4CPUS /* pretend we're smp with 4 ticsers (sic) */
//#define PRETENDNOCAP /* use a terminal without essential caps */ //#define PRETENDNOCAP /* use a terminal without essential caps */
@ -38,7 +39,6 @@
//#define TERMIOS_ONLY /* just limp along with native input only */ //#define TERMIOS_ONLY /* just limp along with native input only */
//#define TTYGETENVYES /* environ vars can override tty col/row */ //#define TTYGETENVYES /* environ vars can override tty col/row */
//#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */ //#define USE_X_COLHDR /* emphasize header vs. whole col, for 'x' */
//#define ZAP_SUSEONLY /* enable the SuSE specific modifications */
/*###### Notes, etc. ###################################################*/ /*###### Notes, etc. ###################################################*/
@ -65,7 +65,7 @@
#define STRSORTCMP strcmp #define STRSORTCMP strcmp
#endif #endif
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
/* FIXME: perhaps making this a function in the suse version of /* FIXME: perhaps making this a function in the suse version of
sysinfo.c was a prelude to hotpluggable updates -- unfortunately, sysinfo.c was a prelude to hotpluggable updates -- unfortunately,
the return value is invariant as currently implemented! */ 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_MEM, P_VRT, P_SWP, P_RES, P_COD, P_DAT, P_SHR,
P_FL1, P_FL2, P_DRT, P_FL1, P_FL2, P_DRT,
P_STA, P_CMD, P_WCH, P_FLG, P_CGR, P_STA, P_CMD, P_WCH, P_FLG, P_CGR,
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
P_OOA, P_OOM, P_OOA, P_OOM,
#endif #endif
#ifdef USE_X_COLHDR #ifdef USE_X_COLHDR
@ -375,11 +375,12 @@ typedef struct WIN_t {
#define SCB_STRS(f,s) \ #define SCB_STRS(f,s) \
static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \ static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \
return Frame_srtflg * STRSORTCMP((*Q)->s, (*P)->s); } 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) { \ static int SCB_NAME(f) (const proc_t **P, const proc_t **Q) { \
if (!(*P)->s || !(*Q)->s) \ if (b) { \
return SORT_eq; \ if (!(*P)->v || !(*Q)->v) return SORT_eq; \
return Frame_srtflg * STRSORTCMP((*Q)->s[0], (*P)->s[0]); } 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 * The following two macros are used to 'inline' those portions of the
@ -532,7 +533,7 @@ typedef struct WIN_t {
" 'd' or <Space> toggles display, 's' sets sort. Use 'q' or <Esc> to end! " \ " 'd' or <Space> toggles display, 's' sets sort. Use 'q' or <Esc> to end! " \
"" ""
#ifdef ZAP_SUSEONLY #ifdef OOMEM_ENABLE
/* w/ 2 extra lines, no room for additional text on 24x80 terminal */ /* w/ 2 extra lines, no room for additional text on 24x80 terminal */
#define FIELDS_notes NULL #define FIELDS_notes NULL
#else #else
@ -634,8 +635,8 @@ typedef struct WIN_t {
#if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH) #if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH)
# error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH' # error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH'
#endif #endif
#if defined(PRETEND4CPUS) && defined (ZAP_SUSEONLY) #if defined(PRETEND4CPUS) && defined (OOMEM_ENABLE)
# error 'PRETEND4CPUS' conflicts with 'ZAP_SUSEONLY' # error 'PRETEND4CPUS' conflicts with 'OOMEM_ENABLE'
#endif #endif