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:
173
proc/readproc.c
173
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) {
|
||||
#define vMAX ( sizeof(dbuf) - (int)(dst - dbuf) )
|
||||
char sbuf[1024], dbuf[1024];
|
||||
char *src, *dst, *grp, *eob, **ret, **q;
|
||||
int align, tot, x;
|
||||
static char** vectorize_this_str (const char* src) {
|
||||
#define pSZ (sizeof(char*))
|
||||
char *cpy, **vec;
|
||||
int adj, tot;
|
||||
|
||||
*(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
|
||||
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;
|
||||
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");
|
||||
else
|
||||
p->cmdline = NULL;
|
||||
|
||||
if (unlikely(flags & PROC_FILLENV)) /* read+parse /proc/#/environ */
|
||||
p->environ = file2strvec(path, "environ");
|
||||
if (unlikely(flags & PROC_FILLENV)) /* read /proc/#/environ */
|
||||
p->environ = file2strvec(path, "environ");
|
||||
else
|
||||
p->environ = NULL;
|
||||
#ifdef ZAP_SUSEONLY
|
||||
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 */
|
||||
#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 */
|
||||
}
|
||||
|
||||
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->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;
|
||||
next_proc:
|
||||
|
Reference in New Issue
Block a user