diff --git a/proc/pids.c b/proc/pids.c index 658f0524..e921b096 100644 --- a/proc/pids.c +++ b/proc/pids.c @@ -49,14 +49,6 @@ #define FILL_ID_MAX 255 // upper limit for pid/uid fills #define MEMORY_INCR 128 // amt by which allocations grow - // these represent the proc_t fields whose storage cannot be managed - // optimally if they are ever referenced more than once in any stack -enum rel_ref { - ref_CGROUP, ref_CMD, ref_CMDLINE, ref_ENVIRON, ref_SD_MACH, - ref_SD_OUID, ref_SD_SEAT, ref_SD_SESS, ref_SD_SLICE, ref_SD_UNIT, - ref_SD_UUNIT, ref_SUPGIDS, ref_SUPGROUPS, - MAXIMUM_ref -}; struct stacks_extent { struct pids_stack **stacks; @@ -89,7 +81,6 @@ struct procps_pidsinfo { PROCTAB *PT; // the old library essential interface unsigned long hertz; // for TIME_ALL & TIME_ELAPSED calculations unsigned long long boot_seconds; // for TIME_ELAPSED calculation - int ref_counts[MAXIMUM_ref]; // ref counts for special string fields PROCTAB *get_PT; // old library interface for active 'get' struct stacks_extent *get_ext; // an extent used for active 'get' enum pids_fetch_type get_type; // last known type of 'get' request @@ -98,37 +89,51 @@ struct procps_pidsinfo { // ___ Results 'Set' Support |||||||||||||||||||||||||||||||||||||||||||||||||| +static char** vectorize_this (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 = calloc(1, tot + adj + (2 * pSZ)); // get new larger buffer + if (!cpy) return NULL; // we no longer use xcalloc + 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 +} // end: vectorize_this + + +#define mkSTR(a) xySTR(a) +#define xySTR(z) #z + #define setNAME(e) set_results_ ## e #define setDECL(e) static void setNAME(e) \ (struct procps_pidsinfo *I, struct pids_result *R, proc_t *P) -// convert pages to kib +/* convert pages to kib */ #define CVT_set(e,t,x) setDECL(e) { \ R->result. t = (long)(P-> x) << I -> pgs2k_shift; } -// strdup of a static char array +/* strdup of a static char array */ #define DUP_set(e,x) setDECL(e) { \ (void)I; R->result.str = strdup(P-> x); } -// regular assignment copy +/* regular assignment copy */ #define REG_set(e,t,x) setDECL(e) { \ (void)I; R->result. t = P-> x; } -// take ownership of a regular char* string if possible, else duplicate +/* take ownership of a normal single string if possible, else return + some sort of hint that they duplicated this char * item ... */ #define STR_set(e,x) setDECL(e) { \ - if (I->ref_counts[ref_ ## e] > 1) R->result.str = strdup(P-> x); \ - else { R->result.str = P-> x; P-> x = NULL; } } -// take ownership of a vectorized single string if possible, else duplicate -#define STV_set(e,x) setDECL(e) { \ - if (I->ref_counts[ref_ ## e] > 1) R->result.str = strdup(*P-> x); \ - else { R->result.str = *P-> x; P-> x = NULL; } } -/* - take ownership of true vectorized strings if possible, else return NULL - [ if there's a source field ref_count, then those true string vectors ] - [ have already been converted into a single string so we return NULL. ] - [ otherwise, the first result struct now gets ownership of those true ] - [ string vectors and any duplicate structures will then receive NULL. ] -*/ -#define VEC_set(e1,e2,x) setDECL(e1) { \ - if (I->ref_counts[ref_ ## e2]) R->result.strv = NULL; \ - else { R->result.strv = P-> x; P-> x = NULL; } } + (void)I; if (NULL != P-> x) { R->result.str = P-> x; P-> x = NULL; } \ + else R->result.str = strdup("[ duplicate " mkSTR(e) " ]"); } +/* take ownership of true vectorized strings if possible, else return + some sort of hint that they duplicated this char ** item ... */ +#define VEC_set(e,x) setDECL(e) { \ + (void)I; if (NULL != P-> x) { R->result.strv = P-> x; P-> x = NULL; } \ + else R->result.strv = vectorize_this("[ duplicate " mkSTR(e) " ]"); } + setDECL(noop) { (void)I; (void)R; (void)P; return; } setDECL(extra) { (void)I; (void)R; (void)P; return; } @@ -138,14 +143,14 @@ REG_set(ADDR_KSTK_ESP, ul_int, kstk_esp) REG_set(ADDR_START_CODE, ul_int, start_code) REG_set(ADDR_START_STACK, ul_int, start_stack) REG_set(ALARM, sl_int, alarm) -setDECL(CGNAME) { char *name = strstr(*P->cgroup, ":name="); if (name && *(name+6)) name += 6; else name = *P->cgroup; R->result.str = strdup(name); } -STV_set(CGROUP, cgroup) -VEC_set(CGROUP_V, CGROUP, cgroup) +STR_set(CGNAME, cgname) +STR_set(CGROUP, cgroup) +VEC_set(CGROUP_V, cgroup_v) STR_set(CMD, cmd) -STV_set(CMDLINE, cmdline) -VEC_set(CMDLINE_V, CMDLINE, cmdline) -STV_set(ENVIRON, environ) -VEC_set(ENVIRON_V, ENVIRON, environ) +STR_set(CMDLINE, cmdline) +VEC_set(CMDLINE_V, cmdline_v) +STR_set(ENVIRON, environ) +VEC_set(ENVIRON_V, environ_v) REG_set(EXIT_SIGNAL, s_int, exit_signal) REG_set(FLAGS, ul_int, flags) REG_set(FLT_MAJ, sl_int, maj_flt) @@ -249,12 +254,15 @@ REG_set(VSIZE_PGS, ul_int, vsize) REG_set(WCHAN_ADDR, ul_int, wchan) setDECL(WCHAN_NAME) { (void)I; R->result.str = strdup(lookup_wchan(P->tid)); } + +#undef mkSTR +#undef xySTR + #undef setDECL #undef CVT_set #undef DUP_set #undef REG_set #undef STR_set -#undef STV_set #undef VEC_set @@ -347,14 +355,15 @@ static int srtNAME(noop) ( #define f_status PROC_FILLSTATUS #define f_systemd PROC_FILLSYSTEMD #define f_usr PROC_FILLUSR + // these next three will yield a single string (never vectorized) +#define x_cgroup PROC_EDITCGRPCVT +#define x_cmdline PROC_EDITCMDLCVT +#define x_environ PROC_EDITENVRCVT // these next three will yield true verctorized strings #define v_arg PROC_FILLARG #define v_cgroup PROC_FILLCGROUP #define v_env PROC_FILLENV - // remaining are compound flags, yielding a single string (maybe vectorized) -#define x_cgroup PROC_EDITCGRPCVT | PROC_FILLCGROUP // just 1 str -#define x_cmdline PROC_EDITCMDLCVT | PROC_FILLARG // just 1 str -#define x_environ PROC_EDITENVRCVT | PROC_FILLENV // just 1 str + // remaining are compound flags #define x_ogroup PROC_FILLSTATUS | PROC_FILLGRP #define x_ouser PROC_FILLSTATUS | PROC_FILLUSR #define x_supgrp PROC_FILLSTATUS | PROC_FILLSUPGRP @@ -378,130 +387,129 @@ static struct { FRE_t freefunc; // free function for strings storage QSR_t sortfunc; // sort cmp func for a specific type int needhist; // a result requires history support - int refcount; // the result needs reference counts } Item_table[] = { -/* setsfunc oldflags freefunc sortfunc needhist refcount - --------------------- ---------- --------- ------------ -------- ------------- */ - { RS(noop), 0, NULL, QS(noop), 0, -1 }, // user only, never altered - { RS(extra), 0, NULL, QS(ull_int), 0, -1 }, // user only, reset to zero - { RS(ADDR_END_CODE), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(ADDR_KSTK_EIP), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(ADDR_KSTK_ESP), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(ADDR_START_CODE), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(ADDR_START_STACK), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(ALARM), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(CGNAME), x_cgroup, FF(str), QS(str), 0, ref_CGROUP }, // refcount: diff result, same source - { RS(CGROUP), x_cgroup, FF(str), QS(str), 0, ref_CGROUP }, // refcount: diff result, same source - { RS(CGROUP_V), v_cgroup, FF(strv), QS(strv), 0, -1 }, - { RS(CMD), f_either, FF(str), QS(str), 0, ref_CMD }, - { RS(CMDLINE), x_cmdline, FF(str), QS(str), 0, ref_CMDLINE }, - { RS(CMDLINE_V), v_arg, FF(strv), QS(strv), 0, -1 }, - { RS(ENVIRON), x_environ, FF(str), QS(str), 0, ref_ENVIRON }, - { RS(ENVIRON_V), v_env, FF(strv), QS(strv), 0, -1 }, - { RS(EXIT_SIGNAL), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(FLAGS), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(FLT_MAJ), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(FLT_MAJ_C), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(FLT_MAJ_DELTA), f_stat, NULL, QS(sl_int), +1, -1 }, - { RS(FLT_MIN), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(FLT_MIN_C), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(FLT_MIN_DELTA), f_stat, NULL, QS(sl_int), +1, -1 }, - { RS(ID_EGID), 0, NULL, QS(u_int), 0, -1 }, // oldflags: free w/ simple_read... - { RS(ID_EGROUP), f_grp, NULL, QS(str), 0, -1 }, - { RS(ID_EUID), 0, NULL, QS(u_int), 0, -1 }, // oldflags: free w/ simple_read... - { RS(ID_EUSER), f_usr, NULL, QS(str), 0, -1 }, - { RS(ID_FGID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_FGROUP), x_ogroup, NULL, QS(str), 0, -1 }, - { RS(ID_FUID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_FUSER), x_ouser, NULL, QS(str), 0, -1 }, - { RS(ID_PGRP), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(ID_PID), 0, NULL, QS(s_int), 0, -1 }, // oldflags: free w/ simple_nextpid - { RS(ID_PPID), f_either, NULL, QS(s_int), 0, -1 }, - { RS(ID_RGID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_RGROUP), x_ogroup, NULL, QS(str), 0, -1 }, - { RS(ID_RUID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_RUSER), x_ouser, NULL, QS(str), 0, -1 }, - { RS(ID_SESSION), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(ID_SGID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_SGROUP), x_ogroup, NULL, QS(str), 0, -1 }, - { RS(ID_SUID), f_status, NULL, QS(u_int), 0, -1 }, - { RS(ID_SUSER), x_ouser, NULL, QS(str), 0, -1 }, - { RS(ID_TGID), 0, NULL, QS(s_int), 0, -1 }, // oldflags: free w/ simple_nextpid - { RS(ID_TPGID), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(LXCNAME), f_lxc, NULL, QS(str), 0, -1 }, - { RS(MEM_CODE), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_CODE_KIB), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_DATA), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_DATA_KIB), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_DT), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_LRS), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_RES), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_RES_KIB), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_SHR), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_SHR_KIB), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_VIRT), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(MEM_VIRT_KIB), f_statm, NULL, QS(sl_int), 0, -1 }, - { RS(NICE), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(NLWP), f_either, NULL, QS(s_int), 0, -1 }, - { RS(NS_IPC), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(NS_MNT), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(NS_NET), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(NS_PID), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(NS_USER), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(NS_UTS), f_ns, NULL, QS(ul_int), 0, -1 }, - { RS(OOM_ADJ), f_oom, NULL, QS(s_int), 0, -1 }, - { RS(OOM_SCORE), f_oom, NULL, QS(s_int), 0, -1 }, - { RS(PRIORITY), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(PROCESSOR), f_stat, NULL, QS(u_int), 0, -1 }, - { RS(RSS), f_stat, NULL, QS(sl_int), 0, -1 }, - { RS(RSS_RLIM), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(RTPRIO), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(SCHED_CLASS), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(SD_MACH), f_systemd, FF(str), QS(str), 0, ref_SD_MACH }, - { RS(SD_OUID), f_systemd, FF(str), QS(str), 0, ref_SD_OUID }, - { RS(SD_SEAT), f_systemd, FF(str), QS(str), 0, ref_SD_SEAT }, - { RS(SD_SESS), f_systemd, FF(str), QS(str), 0, ref_SD_SESS }, - { RS(SD_SLICE), f_systemd, FF(str), QS(str), 0, ref_SD_SLICE }, - { RS(SD_UNIT), f_systemd, FF(str), QS(str), 0, ref_SD_UNIT }, - { RS(SD_UUNIT), f_systemd, FF(str), QS(str), 0, ref_SD_UUNIT }, - { RS(SIGBLOCKED), f_status, FF(str), QS(str), 0, -1 }, - { RS(SIGCATCH), f_status, FF(str), QS(str), 0, -1 }, - { RS(SIGIGNORE), f_status, FF(str), QS(str), 0, -1 }, - { RS(SIGNALS), f_status, FF(str), QS(str), 0, -1 }, - { RS(SIGPENDING), f_status, FF(str), QS(str), 0, -1 }, - { RS(STATE), f_either, NULL, QS(s_ch), 0, -1 }, - { RS(SUPGIDS), f_status, FF(str), QS(str), 0, ref_SUPGIDS }, - { RS(SUPGROUPS), x_supgrp, FF(str), QS(str), 0, ref_SUPGROUPS }, - { RS(TICS_ALL), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TICS_ALL_C), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TICS_DELTA), f_stat, NULL, QS(sl_int), +1, -1 }, - { RS(TICS_SYSTEM), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TICS_SYSTEM_C), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TICS_USER), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TICS_USER_C), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TIME_ALL), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TIME_ELAPSED), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TIME_START), f_stat, NULL, QS(ull_int), 0, -1 }, - { RS(TTY), f_stat, NULL, QS(s_int), 0, -1 }, - { RS(TTY_NAME), f_stat, FF(str), QS(strvers), 0, -1 }, - { RS(TTY_NUMBER), f_stat, FF(str), QS(strvers), 0, -1 }, - { RS(VM_DATA), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_EXE), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_LIB), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_RSS), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_RSS_ANON), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_RSS_FILE), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_RSS_LOCKED), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_RSS_SHARED), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_SIZE), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_STACK), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_SWAP), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VM_USED), f_status, NULL, QS(sl_int), 0, -1 }, - { RS(VSIZE_PGS), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(WCHAN_ADDR), f_stat, NULL, QS(ul_int), 0, -1 }, - { RS(WCHAN_NAME), 0, FF(str), QS(str), 0, -1 }, // oldflags: tid already free +/* setsfunc oldflags freefunc sortfunc needhist + --------------------- ---------- --------- ------------- -------- */ + { RS(noop), 0, NULL, QS(noop), 0 }, // user only, never altered + { RS(extra), 0, NULL, QS(ull_int), 0 }, // user only, reset to zero + { RS(ADDR_END_CODE), f_stat, NULL, QS(ul_int), 0 }, + { RS(ADDR_KSTK_EIP), f_stat, NULL, QS(ul_int), 0 }, + { RS(ADDR_KSTK_ESP), f_stat, NULL, QS(ul_int), 0 }, + { RS(ADDR_START_CODE), f_stat, NULL, QS(ul_int), 0 }, + { RS(ADDR_START_STACK), f_stat, NULL, QS(ul_int), 0 }, + { RS(ALARM), f_stat, NULL, QS(sl_int), 0 }, + { RS(CGNAME), x_cgroup, FF(str), QS(str), 0 }, + { RS(CGROUP), x_cgroup, FF(str), QS(str), 0 }, + { RS(CGROUP_V), v_cgroup, FF(strv), QS(strv), 0 }, + { RS(CMD), f_either, FF(str), QS(str), 0 }, + { RS(CMDLINE), x_cmdline, FF(str), QS(str), 0 }, + { RS(CMDLINE_V), v_arg, FF(strv), QS(strv), 0 }, + { RS(ENVIRON), x_environ, FF(str), QS(str), 0 }, + { RS(ENVIRON_V), v_env, FF(strv), QS(strv), 0 }, + { RS(EXIT_SIGNAL), f_stat, NULL, QS(s_int), 0 }, + { RS(FLAGS), f_stat, NULL, QS(ul_int), 0 }, + { RS(FLT_MAJ), f_stat, NULL, QS(sl_int), 0 }, + { RS(FLT_MAJ_C), f_stat, NULL, QS(sl_int), 0 }, + { RS(FLT_MAJ_DELTA), f_stat, NULL, QS(sl_int), +1 }, + { RS(FLT_MIN), f_stat, NULL, QS(sl_int), 0 }, + { RS(FLT_MIN_C), f_stat, NULL, QS(sl_int), 0 }, + { RS(FLT_MIN_DELTA), f_stat, NULL, QS(sl_int), +1 }, + { RS(ID_EGID), 0, NULL, QS(u_int), 0 }, // oldflags: free w/ simple_read... + { RS(ID_EGROUP), f_grp, NULL, QS(str), 0 }, + { RS(ID_EUID), 0, NULL, QS(u_int), 0 }, // oldflags: free w/ simple_read... + { RS(ID_EUSER), f_usr, NULL, QS(str), 0 }, + { RS(ID_FGID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_FGROUP), x_ogroup, NULL, QS(str), 0 }, + { RS(ID_FUID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_FUSER), x_ouser, NULL, QS(str), 0 }, + { RS(ID_PGRP), f_stat, NULL, QS(s_int), 0 }, + { RS(ID_PID), 0, NULL, QS(s_int), 0 }, // oldflags: free w/ simple_nextpid + { RS(ID_PPID), f_either, NULL, QS(s_int), 0 }, + { RS(ID_RGID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_RGROUP), x_ogroup, NULL, QS(str), 0 }, + { RS(ID_RUID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_RUSER), x_ouser, NULL, QS(str), 0 }, + { RS(ID_SESSION), f_stat, NULL, QS(s_int), 0 }, + { RS(ID_SGID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_SGROUP), x_ogroup, NULL, QS(str), 0 }, + { RS(ID_SUID), f_status, NULL, QS(u_int), 0 }, + { RS(ID_SUSER), x_ouser, NULL, QS(str), 0 }, + { RS(ID_TGID), 0, NULL, QS(s_int), 0 }, // oldflags: free w/ simple_nextpid + { RS(ID_TPGID), f_stat, NULL, QS(s_int), 0 }, + { RS(LXCNAME), f_lxc, NULL, QS(str), 0 }, + { RS(MEM_CODE), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_CODE_KIB), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_DATA), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_DATA_KIB), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_DT), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_LRS), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_RES), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_RES_KIB), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_SHR), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_SHR_KIB), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_VIRT), f_statm, NULL, QS(sl_int), 0 }, + { RS(MEM_VIRT_KIB), f_statm, NULL, QS(sl_int), 0 }, + { RS(NICE), f_stat, NULL, QS(sl_int), 0 }, + { RS(NLWP), f_either, NULL, QS(s_int), 0 }, + { RS(NS_IPC), f_ns, NULL, QS(ul_int), 0 }, + { RS(NS_MNT), f_ns, NULL, QS(ul_int), 0 }, + { RS(NS_NET), f_ns, NULL, QS(ul_int), 0 }, + { RS(NS_PID), f_ns, NULL, QS(ul_int), 0 }, + { RS(NS_USER), f_ns, NULL, QS(ul_int), 0 }, + { RS(NS_UTS), f_ns, NULL, QS(ul_int), 0 }, + { RS(OOM_ADJ), f_oom, NULL, QS(s_int), 0 }, + { RS(OOM_SCORE), f_oom, NULL, QS(s_int), 0 }, + { RS(PRIORITY), f_stat, NULL, QS(s_int), 0 }, + { RS(PROCESSOR), f_stat, NULL, QS(u_int), 0 }, + { RS(RSS), f_stat, NULL, QS(sl_int), 0 }, + { RS(RSS_RLIM), f_stat, NULL, QS(ul_int), 0 }, + { RS(RTPRIO), f_stat, NULL, QS(ul_int), 0 }, + { RS(SCHED_CLASS), f_stat, NULL, QS(ul_int), 0 }, + { RS(SD_MACH), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_OUID), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_SEAT), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_SESS), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_SLICE), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_UNIT), f_systemd, FF(str), QS(str), 0 }, + { RS(SD_UUNIT), f_systemd, FF(str), QS(str), 0 }, + { RS(SIGBLOCKED), f_status, FF(str), QS(str), 0 }, + { RS(SIGCATCH), f_status, FF(str), QS(str), 0 }, + { RS(SIGIGNORE), f_status, FF(str), QS(str), 0 }, + { RS(SIGNALS), f_status, FF(str), QS(str), 0 }, + { RS(SIGPENDING), f_status, FF(str), QS(str), 0 }, + { RS(STATE), f_either, NULL, QS(s_ch), 0 }, + { RS(SUPGIDS), f_status, FF(str), QS(str), 0 }, + { RS(SUPGROUPS), x_supgrp, FF(str), QS(str), 0 }, + { RS(TICS_ALL), f_stat, NULL, QS(ull_int), 0 }, + { RS(TICS_ALL_C), f_stat, NULL, QS(ull_int), 0 }, + { RS(TICS_DELTA), f_stat, NULL, QS(sl_int), +1 }, + { RS(TICS_SYSTEM), f_stat, NULL, QS(ull_int), 0 }, + { RS(TICS_SYSTEM_C), f_stat, NULL, QS(ull_int), 0 }, + { RS(TICS_USER), f_stat, NULL, QS(ull_int), 0 }, + { RS(TICS_USER_C), f_stat, NULL, QS(ull_int), 0 }, + { RS(TIME_ALL), f_stat, NULL, QS(ull_int), 0 }, + { RS(TIME_ELAPSED), f_stat, NULL, QS(ull_int), 0 }, + { RS(TIME_START), f_stat, NULL, QS(ull_int), 0 }, + { RS(TTY), f_stat, NULL, QS(s_int), 0 }, + { RS(TTY_NAME), f_stat, FF(str), QS(strvers), 0 }, + { RS(TTY_NUMBER), f_stat, FF(str), QS(strvers), 0 }, + { RS(VM_DATA), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_EXE), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_LIB), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_RSS), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_RSS_ANON), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_RSS_FILE), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_RSS_LOCKED), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_RSS_SHARED), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_SIZE), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_STACK), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_SWAP), f_status, NULL, QS(sl_int), 0 }, + { RS(VM_USED), f_status, NULL, QS(sl_int), 0 }, + { RS(VSIZE_PGS), f_stat, NULL, QS(ul_int), 0 }, + { RS(WCHAN_ADDR), f_stat, NULL, QS(ul_int), 0 }, + { RS(WCHAN_NAME), 0, FF(str), QS(str), 0 }, // oldflags: tid already free // dummy entry corresponding to PROCPS_PIDS_logical_end ... - { NULL, 0, NULL, NULL, 0, -1 } + { NULL, 0, NULL, NULL, 0 } }; // next MUST be kept in sync with highest value enum @@ -907,17 +915,14 @@ static inline void libflags_set ( struct procps_pidsinfo *info) { enum pids_item e; - int i, n; + int i; - memset (info->ref_counts, 0, sizeof(info->ref_counts)); info->oldflags = info->history_yes = 0; for (i = 0; i < info->curitems; i++) { if (((e = info->items[i])) >= PROCPS_PIDS_logical_end) break; info->oldflags |= Item_table[e].oldflags; info->history_yes |= Item_table[e].needhist; - n = Item_table[e].refcount; - if (n > -1) ++info->ref_counts[n]; } if (info->oldflags & f_either) { if (!(info->oldflags & f_stat)) diff --git a/proc/readproc.c b/proc/readproc.c index b7591892..d87eeac6 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -91,19 +91,23 @@ static inline void free_acquired (proc_t *p, int reuse) { #ifdef QUICK_THREADS if (!IS_THREAD(p)) { #endif - if (p->environ) free((void*)*p->environ); - if (p->cmdline) free((void*)*p->cmdline); - if (p->cgroup) free((void*)*p->cgroup); - if (p->supgid) free(p->supgid); - if (p->supgrp) free(p->supgrp); - if (p->cmd) free(p->cmd); - if (p->sd_mach) free(p->sd_mach); - if (p->sd_ouid) free(p->sd_ouid); - if (p->sd_seat) free(p->sd_seat); - if (p->sd_sess) free(p->sd_sess); - if (p->sd_slice) free(p->sd_slice); - if (p->sd_unit) free(p->sd_unit); - if (p->sd_uunit) free(p->sd_uunit); + if (p->environ) free((void*)p->environ); + if (p->cmdline) free((void*)p->cmdline); + if (p->cgname) free((void*)p->cgname); + if (p->cgroup) free((void*)p->cgroup); + if (p->environ_v) free((void*)*p->environ_v); + if (p->cmdline_v) free((void*)*p->cmdline_v); + if (p->cgroup_v) free((void*)*p->cgroup_v); + if (p->supgid) free(p->supgid); + if (p->supgrp) free(p->supgrp); + if (p->cmd) free(p->cmd); + if (p->sd_mach) free(p->sd_mach); + if (p->sd_ouid) free(p->sd_ouid); + if (p->sd_seat) free(p->sd_seat); + if (p->sd_sess) free(p->sd_sess); + if (p->sd_slice) free(p->sd_slice); + if (p->sd_unit) free(p->sd_unit); + if (p->sd_uunit) free(p->sd_uunit); #ifdef QUICK_THREADS } #endif @@ -713,28 +717,11 @@ static int read_unvectored(char *restrict const dst, unsigned sz, const char* wh return n; } -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(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 a 'cgroup' for the designated proc_t. - // It is similar to file2strvec except we filter and concatenate - // the data into a single string represented as a single vector. + // This routine reads a 'cgroup' for the designated proc_t and + // guarantees the caller a valid proc_t.cgroup pointer. static void fill_cgroup_cvt (const char* directory, proc_t *restrict p) { #define vMAX ( MAX_BUFSZ - (int)(dst - dst_buffer) ) - char *src, *dst, *grp, *eob; + char *src, *dst, *grp, *eob, *name; int tot, x, whackable_int = MAX_BUFSZ; *(dst = dst_buffer) = '\0'; // empty destination @@ -750,13 +737,17 @@ static void fill_cgroup_cvt (const char* directory, proc_t *restrict p) { dst += snprintf(dst, vMAX, "%s", (dst > dst_buffer) ? "," : ""); dst += escape_str(dst, grp, vMAX, &whackable_int); } - p->cgroup = vectorize_this_str(dst_buffer[0] ? dst_buffer : "-"); + p->cgroup = strdup(dst_buffer[0] ? dst_buffer : "-"); + + name = strstr(p->cgroup, ":name="); + if (name && *(name+6)) name += 6; else name = p->cgroup; + p->cgname = strdup(name); #undef vMAX } // This routine reads a 'cmdline' for the designated proc_t, "escapes" - // the result into a single string represented as a single vector - // and guarantees the caller a valid proc_t.cmdline pointer. + // the result into a single string while guaranteeing the caller a + // valid proc_t.cmdline pointer. static void fill_cmdline_cvt (const char* directory, proc_t *restrict p) { #define uFLG ( ESC_BRACKETS | ESC_DEFUNCT ) int whackable_int = MAX_BUFSZ; @@ -765,7 +756,7 @@ static void fill_cmdline_cvt (const char* directory, proc_t *restrict p) { escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int); else escape_command(dst_buffer, p, MAX_BUFSZ, &whackable_int, uFLG); - p->cmdline = vectorize_this_str(dst_buffer); + p->cmdline = strdup(dst_buffer[0] ? dst_buffer : "?"); #undef uFLG } @@ -777,7 +768,7 @@ static void fill_environ_cvt (const char* directory, proc_t *restrict p) { dst_buffer[0] = '\0'; if (read_unvectored(src_buffer, MAX_BUFSZ, directory, "environ", ' ')) escape_str(dst_buffer, src_buffer, MAX_BUFSZ, &whackable_int); - p->environ = vectorize_this_str(dst_buffer[0] ? dst_buffer : "-"); + p->environ = strdup(dst_buffer[0] ? dst_buffer : "-"); } @@ -924,29 +915,20 @@ static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict cons } } - if (flags & PROC_FILLENV) { // read /proc/#/environ - if (flags & PROC_EDITENVRCVT) - fill_environ_cvt(path, p); - else - p->environ = file2strvec(path, "environ"); - } else - p->environ = NULL; + if (flags & PROC_FILLENV) // read /proc/#/environ + p->environ_v = file2strvec(path, "environ"); + if (flags & PROC_EDITENVRCVT) + fill_environ_cvt(path, p); - if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/cmdline - if (flags & PROC_EDITCMDLCVT) - fill_cmdline_cvt(path, p); - else - p->cmdline = file2strvec(path, "cmdline"); - } else - p->cmdline = NULL; + if (flags & PROC_FILLARG) // read /proc/#/cmdline + p->cmdline_v = file2strvec(path, "cmdline"); + if (flags & PROC_EDITCMDLCVT) + fill_cmdline_cvt(path, p); - if ((flags & PROC_FILLCGROUP)) { // read /proc/#/cgroup - if (flags & PROC_EDITCGRPCVT) - fill_cgroup_cvt(path, p); - else - p->cgroup = file2strvec(path, "cgroup"); - } else - p->cgroup = NULL; + if ((flags & PROC_FILLCGROUP)) // read /proc/#/cgroup + p->cgroup_v = file2strvec(path, "cgroup"); + if (flags & PROC_EDITCGRPCVT) + fill_cgroup_cvt(path, p); if (flags & PROC_FILLOOM) { if (file2str(path, "oom_score", &ub) != -1) @@ -1046,29 +1028,20 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric if (flags & PROC_FILLSUPGRP) supgrps_from_supgids(t); #endif - if (flags & PROC_FILLENV) { // read /proc/#/task/#/environ - if (flags & PROC_EDITENVRCVT) - fill_environ_cvt(path, t); - else - t->environ = file2strvec(path, "environ"); - } else - t->environ = NULL; + if (flags & PROC_FILLENV) // read /proc/#/task/#/environ + t->environ_v = file2strvec(path, "environ"); + if (flags & PROC_EDITENVRCVT) + fill_environ_cvt(path, t); - if (flags & (PROC_FILLCOM|PROC_FILLARG)) { // read /proc/#/task/#/cmdline - if (flags & PROC_EDITCMDLCVT) - fill_cmdline_cvt(path, t); - else - t->cmdline = file2strvec(path, "cmdline"); - } else - t->cmdline = NULL; + if (flags & PROC_FILLARG) // read /proc/#/task/#/cmdline + t->cmdline_v = file2strvec(path, "cmdline"); + if (flags & PROC_EDITCMDLCVT) + fill_cmdline_cvt(path, t); - if ((flags & PROC_FILLCGROUP)) { // read /proc/#/task/#/cgroup - if (flags & PROC_EDITCGRPCVT) - fill_cgroup_cvt(path, t); - else - t->cgroup = file2strvec(path, "cgroup"); - } else - t->cgroup = NULL; + if ((flags & PROC_FILLCGROUP)) // read /proc/#/task/#/cgroup + t->cgroup_v = file2strvec(path, "cgroup"); + if (flags & PROC_EDITCGRPCVT) + fill_cgroup_cvt(path, t); if (flags & PROC_FILLSYSTEMD) // get sd-login.h stuff sd2proc(t); @@ -1078,26 +1051,30 @@ static proc_t* simple_readtask(PROCTAB *restrict const PT, const proc_t *restric #ifdef QUICK_THREADS } else { - t->size = p->size; - t->resident = p->resident; - t->share = p->share; - t->trs = p->trs; - t->lrs = p->lrs; - t->drs = p->drs; - t->dt = p->dt; - t->cmdline = p->cmdline; // better not free these until done with all threads! - t->environ = p->environ; - t->cgroup = p->cgroup; - t->supgid = p->supgid; - t->supgrp = p->supgrp; - t->sd_mach = p->sd_mach; - t->sd_ouid = p->sd_ouid; - t->sd_seat = p->sd_seat; - t->sd_sess = p->sd_sess; - t->sd_slice = p->sd_slice; - t->sd_unit = p->sd_unit; - t->sd_uunit = p->sd_uunit; - t->lxcname = p->lxcname; + t->size = p->size; + t->resident = p->resident; + t->share = p->share; + t->trs = p->trs; + t->lrs = p->lrs; + t->drs = p->drs; + t->dt = p->dt; + t->cmdline = p->cmdline; // better not free these until done with all threads! + t->cmdline_v = p->cmdline_v; + t->environ = p->environ; + t->environ_v = p->environ_v; + t->cgname = p->cgname; + t->cgroup = p->cgroup; + t->cgroup_v = p->cgroup_v; + t->supgid = p->supgid; + t->supgrp = p->supgrp; + t->sd_mach = p->sd_mach; + t->sd_ouid = p->sd_ouid; + t->sd_seat = p->sd_seat; + t->sd_sess = p->sd_sess; + t->sd_slice = p->sd_slice; + t->sd_unit = p->sd_unit; + t->sd_uunit = p->sd_uunit; + t->lxcname = p->lxcname; MK_THREAD(t); } #endif diff --git a/proc/readproc.h b/proc/readproc.h index ec51749e..65e771c6 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -124,11 +124,15 @@ 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) - **cgroup, // (special) cgroup string vector (/proc/#/cgroup) - *supgid, // status supplementary gids as comma delimited str - *supgrp; // supp grp names as comma delimited str, derived from supgid + *environ, // (special) environment as string (/proc/#/environ) + *cmdline, // (special) command line as string (/proc/#/cmdline) + *cgroup, // (special) cgroup as string (/proc/#/cgroup) + *cgname, // (special) name portion of above (if possible) + *supgid, // status supplementary gids as comma delimited str + *supgrp, // supp grp names as comma delimited str, derived from supgid + **environ_v, // (special) environment string vectors (/proc/#/environ) + **cmdline_v, // (special) command line string vectors (/proc/#/cmdline) + **cgroup_v; // (special) cgroup string vectors (/proc/#/cgroup) char *euser, // stat(),status effective user name *ruser, // status real user name @@ -213,14 +217,13 @@ typedef struct PROCTAB { // id's since uid_t supports no convenient termination sentinel.) #define PROC_FILLMEM 0x0001 // read statm -#define PROC_FILLCOM 0x0002 // alloc and fill in `cmdline' -#define PROC_FILLENV 0x0004 // alloc and fill in `environ' +#define PROC_FILLARG 0x0002 // alloc and fill in `cmdline' vectors +#define PROC_FILLENV 0x0004 // alloc and fill in `environ' vectors #define PROC_FILLUSR 0x0008 // resolve user id number -> user name #define PROC_FILLGRP 0x0010 // resolve group id number -> group name #define PROC_FILLSTATUS 0x0020 // read status #define PROC_FILLSTAT 0x0040 // read stat -#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline' -#define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup` +#define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup` vectors #define PROC_FILLSUPGRP 0x0400 // resolve supplementary group id -> group name #define PROC_FILLOOM 0x0800 // fill in proc_t oom_score and oom_adj #define PROC_FILLNS 0x8000 // fill in proc_t namespace information @@ -233,9 +236,9 @@ typedef struct PROCTAB { #define PROC_PID 0x1000 // process id numbers ( 0 terminated) #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 -#define PROC_EDITENVRCVT 0x40000 // edit `environ' as single vector +#define PROC_EDITCGRPCVT 0x10000 // edit `cgroup' as regular string +#define PROC_EDITCMDLCVT 0x20000 // edit `cmdline' as regular string +#define PROC_EDITENVRCVT 0x40000 // edit `environ' as regular string // it helps to give app code a few spare bits #define PROC_SPARE_1 0x01000000