enhanced libproc cgroup/cmdline support, exploited by top
authorJim Warner <james.warner@comcast.net>
Wed, 18 May 2011 08:33:44 +0000 (10:33 +0200)
committerJan Görig <jgorig@redhat.com>
Wed, 18 May 2011 08:33:44 +0000 (10:33 +0200)
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>
proc/escape.c
proc/escape.h
proc/library.map
proc/readproc.c
proc/readproc.h
proc/sysinfo.c
proc/sysinfo.h
ps/display.c
ps/output.c
top.c
top.h

index 0eb1418bde0d5aff372bebb9a3856b6dc4441dca..92ba4b195e8ca13952b4db846e49e51a5191aebb 100644 (file)
@@ -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;
+}
index 172960f5842c2a8dfef49c90841718636c43c584..aa9f6d647d7c1a45c679cbed3b358e2fe9aca118 100644 (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_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
index b438849e828e4a58724b2a9e1dd35df129caa8e5..032ada0c67057d07b166c85c846951822bff8c74 100644 (file)
@@ -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;
index 10146f0befcb16ae769572dbd49eeaf5b0f4c897..b96d0a45823e17b8c21a28df4f35d0a6815b12d3 100644 (file)
@@ -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:
index c6c9bbe2f1345c4c837f80b75a5ec7ea52ac0208..b8d97bb317989b3fbd52769294ac7457748fbe59 100644 (file)
@@ -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
index 2f26d74dc20cd76dc7ed0929831d4fb00ea76a04..952faf416bf58fc7d5acc029374db8f95f6d0478 100644 (file)
@@ -24,7 +24,7 @@
 #include <netinet/in.h>  /* 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
   //
index 98344777fdb8d2e2f58b1182a487dcbe799693ce..744f2805ac5d6d46c2c6afee082d6fb8b23ab18d 100644 (file)
@@ -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 */
index 3d6bbded9b9af9fcb25293a8a54f8dee9e387dda..035a88405e7d63b562d3e2546b89ccfee10440ae 100644 (file)
@@ -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){
index e21691405b8ab096122dd3e2088d5d61fef5e68b..6063c903297dec8d959d265aa46bec574872bd44 100644 (file)
@@ -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 b7ca1328238314294fd79c3a0d0230b3bbb95f73..06841cbe64f722c53ed655cee20fb6197988910d 100644 (file)
--- a/top.c
+++ b/top.c
@@ -40,7 +40,6 @@
 #include <values.h>
 
 #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 580266dca3ebd721a3428b8abb425a591dd434df..804eec40c2d2a68472240b70d9a62bc6b44d5c99 100644 (file)
--- 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 <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 */
 #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