diff options
author | Jim Warner <james.warner@comcast.net> | 2011-05-18 10:33:44 +0200 |
---|---|---|
committer | Jan Görig <jgorig@redhat.com> | 2011-05-18 10:33:44 +0200 |
commit | 7b0fc19e9d28380dc9790615b93bc3653d6d686e (patch) | |
tree | 844b4136dd63dedda7b1834d64cdd41f0b7a72a6 /proc/readproc.c | |
parent | 8621387c774df2cac53090f59de6b109d1af9786 (diff) | |
download | procps-ng-newtop.tar.gz |
enhanced libproc cgroup/cmdline support, exploited by topnewtop
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>
Diffstat (limited to 'proc/readproc.c')
-rw-r--r-- | proc/readproc.c | 169 |
1 files changed, 100 insertions, 69 deletions
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: |