Description: 506303 ps displays supplementary groups Author: Alfredo Esteban Bug-Debian: http://bugs.debian.org/506303 Reviewed-by: Craig Small --- a/proc/library.map +++ b/proc/library.map @@ -7,7 +7,7 @@ readproc; readtask; readproctab; readproctab2; look_up_our_self; escape_command; escape_str; escape_strlist; - openproc; closeproc; freeproc; + openproc; closeproc; freeproc; allocsupgrp; freesupgrp; tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; lookup_wchan; display_version; procps_version; linux_version_code; Hertz; smp_num_cpus; have_privs; --- a/proc/readproc.c +++ b/proc/readproc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -85,63 +86,68 @@ long Threads = 0; long Tgid = 0; long Pid = 0; + int hash = 0; + int isupgid = 0; - static const unsigned char asso[] = + static const unsigned char asso[] = { - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 15, 61, - 61, 61, 61, 61, 61, 61, 30, 3, 5, 5, - 61, 5, 61, 8, 61, 61, 3, 61, 10, 61, - 6, 61, 13, 0, 30, 25, 0, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 3, 61, 13, - 0, 0, 61, 30, 61, 25, 61, 61, 61, 0, - 61, 61, 61, 61, 5, 61, 0, 61, 61, 61, - 0, 61, 61, 61, 61, 61, 61, 61 + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 0, 66, + 66, 66, 66, 66, 66, 66, 3, 30, 20, 30, + 66, 25, 66, 20, 66, 66, 30, 66, 25, 66, + 0, 66, 8, 10, 3, 18, 5, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 3, 66, 10, + 0, 0, 66, 25, 66, 5, 66, 66, 66, 25, + 66, 5, 66, 66, 0, 66, 0, 0, 66, 66, + 25, 66, 66, 66, 66, 66, 66, 66 }; static const status_table_struct table[] = { - F(VmStk) + F(Pid) NUL NUL - F(State) + F(Threads) + NUL + F(PPid) + NUL NUL + F(Tgid) NUL - F(VmExe) F(ShdPnd) + NUL NUL + F(State) NUL - F(VmData) + F(VmStk) + NUL NUL + F(Uid) NUL - F(Name) + F(VmSize) NUL NUL F(VmRSS) - NUL NUL - F(VmLck) - NUL NUL NUL + NUL F(Gid) - F(Pid) - NUL NUL NUL - F(VmSize) NUL NUL - F(VmLib) - NUL NUL - F(PPid) - NUL - F(SigCgt) + F(VmData) NUL - F(Threads) + F(Groups) + NUL NUL NUL NUL F(SigPnd) + NUL NUL + F(SigBlk) NUL + F(VmLib) + NUL NUL NUL NUL + F(VmLck) + NUL NUL NUL NUL + F(Name) + NUL NUL NUL NUL F(SigIgn) - NUL - F(Uid) - NUL NUL NUL NUL NUL NUL NUL NUL NUL - NUL NUL NUL NUL NUL - F(Tgid) NUL NUL NUL NUL - F(SigBlk) - NUL NUL NUL + F(VmExe) + NUL NUL NUL NUL + F(SigCgt) }; #undef F @@ -157,6 +163,9 @@ P->vm_exe = 0; P->vm_lib = 0; P->nlwp = 0; + P->nsupgid = 0; + P->supgid = NULL; + P->supgrp = NULL; P->signal[0] = '\0'; // so we can detect it as missing for very old kernels goto base; @@ -173,7 +182,9 @@ // examine a field name (hash and compare) base: if(unlikely(!*S)) break; - entry = table[63 & (asso[(int)S[3]] + asso[(int)S[2]] + asso[(int)S[0]])]; + hash = asso[S[3]] + asso[S[2]] + asso[S[0]]; + if (hash > 65) continue; + entry = table[hash]; colon = strchr(S, ':'); if(unlikely(!colon)) break; if(unlikely(colon[1]!='\t')) break; @@ -271,6 +282,21 @@ P->sgid = strtol(S,&S,10); P->fgid = strtol(S,&S,10); continue; + case_Groups: + isupgid = 0; + if (*S != '\n'){ // Is there any supplementary group ? + P->supgid = (int *) xmalloc(0x0004 * sizeof(int)); + int vctsize = 0x0004; + while (S[1] != '\n' && isupgidsupgid = (int *)xrealloc(P->supgid,vctsize * sizeof(int)); + } + P->supgid[isupgid++] = strtol(S,&S,10); + P->nsupgid++; + } + } + continue; case_VmData: P->vm_data = strtol(S,&S,10); continue; @@ -589,6 +615,13 @@ } } + if (flags & PROC_FILLSUPGRP && p->nsupgid > 0){ + allocsupgrp(p); + int i; + for (i=0; i < p->nsupgid; i++) + memcpy(p->supgrp[i], group_from_gid(p->supgid[i]), P_G_SZ); + } + if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */ p->cmdline = file2strvec(path, "cmdline"); else @@ -683,6 +716,13 @@ } } + if (flags & PROC_FILLSUPGRP && t->nsupgid > 0){ + allocsupgrp(t); + int i; + for (i=0; i < t->nsupgid; i++) + memcpy(t->supgrp[i], group_from_gid(t->supgid[i]), P_G_SZ); + } + #if 0 if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */ t->cmdline = file2strvec(path, "cmdline"); @@ -897,6 +937,23 @@ } } +// allocate memory for supgrp +void allocsupgrp(proc_t *p) { + if (!p || p->nsupgid == 0) return; + p->supgrp = (char**)xmalloc(p->nsupgid * sizeof(char*)); + int i; + for (i=0; insupgid; i++) + p->supgrp[i] = (char*)xmalloc(P_G_SZ * sizeof(char)); +} + +// free memory allocated for supgrp +void freesupgrp(proc_t *p) { + int i; + for (i=0; insupgid; i++) + if (p->supgrp[i]) free(p->supgrp[i]); + free(p->supgrp); +} + // deallocate the space allocated by readproc if the passed rbuf was NULL void freeproc(proc_t* p) { if (!p) /* in case p is NULL */ --- a/proc/readproc.h +++ b/proc/readproc.h @@ -122,6 +122,7 @@ egroup[P_G_SZ], // status effective group name sgroup[P_G_SZ], // status saved group name fgroup[P_G_SZ], // status filesystem group name + **supgrp, // status supplementary groups cmd[16]; // stat,status basename of executable file in call to exec(2) struct proc_t *ring, // n/a thread group ring @@ -137,6 +138,8 @@ suid, sgid, // status saved fuid, fgid, // status fs (used for file access only) tpgid, // stat terminal process group id + nsupgid, // status number of supplementary groups + *supgid, // status supplementary gid's exit_signal, // stat might not be SIGCHLD processor; // stat current (or most recent?) CPU char **cgroup; // cgroup current cgroup, looks like a classic filepath @@ -198,6 +201,12 @@ // clean-up open files, etc from the openproc() extern void closeproc(PROCTAB* PT); +// allocate memory for supgrp +extern void allocsupgrp(proc_t *p); + +// free memory allocated for supgrp +extern void freesupgrp(proc_t *p); + // retrieve the next process matching the criteria set by the openproc() extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p); extern proc_t* readtask(PROCTAB *restrict const PT, const proc_t *restrict const p, proc_t *restrict t); @@ -238,6 +247,7 @@ #define PROC_FILLWCHAN 0x0080 // look up WCHAN name #define PROC_FILLARG 0x0100 // alloc and fill in `cmdline' #define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup` +#define PROC_FILLSUPGRP 0x0400 // resolve supplementary group id number -> group name #define PROC_LOOSE_TASKS 0x2000 // threat threads as if they were processes --- a/ps/display.c +++ b/ps/display.c @@ -342,6 +342,8 @@ if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse if(buf.environ) free((void*)*buf.environ); // ought to reuse if(buf.cgroup) free((void*)*buf.cgroup); + if(buf.nsupgid > 0 && buf.supgid) free(buf.supgid); + if((ptp->flags & PROC_FILLSUPGRP) && buf.nsupgid>0 && buf.supgrp) freesupgrp(&buf); } break; case TF_show_proc|TF_loose_tasks: // H option @@ -349,12 +351,16 @@ proc_t buf2; // must still have the process allocated while(readtask(ptp,&buf,&buf2)){ - if(!want_this_proc(&buf)) continue; - show_one_proc(&buf2, task_format_list); + if(want_this_proc(&buf)) show_one_proc(&buf2, task_format_list); + if(buf2.nsupgid > 0 && buf2.supgid && buf.supgid!=buf2.supgid) free(buf2.supgid); + if((ptp->flags & PROC_FILLSUPGRP) && buf2.nsupgid>0 && buf2.supgrp && buf.supgrp!=buf2.supgrp) + freesupgrp(&buf2); } if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse if(buf.environ) free((void*)*buf.environ); // ought to reuse if(buf.cgroup) free((void*)*buf.cgroup); + if(buf.nsupgid > 0 && buf.supgid) free(buf.supgid); + if((ptp->flags & PROC_FILLSUPGRP) && buf.nsupgid>0 && buf.supgrp) freesupgrp(&buf); } break; case TF_show_proc|TF_show_task: // m and -m options @@ -363,11 +369,18 @@ proc_t buf2; show_one_proc(&buf, proc_format_list); // must still have the process allocated - while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list); + while(readtask(ptp,&buf,&buf2)){ + show_one_proc(&buf2, task_format_list); + if(buf2.nsupgid > 0 && buf2.supgid && buf.supgid!=buf2.supgid) free(buf2.supgid); + if(ptp->flags & PROC_FILLSUPGRP && buf2.nsupgid>0 && buf2.supgrp && buf.supgrp!=buf2.supgrp) + freesupgrp(&buf2); + } } if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse if(buf.environ) free((void*)*buf.environ); // ought to reuse if(buf.cgroup) free((void*)*buf.cgroup); + if(buf.nsupgid > 0 && buf.supgid) free(buf.supgid); + if((ptp->flags & PROC_FILLSUPGRP) && buf.nsupgid>0 && buf.supgrp) freesupgrp(&buf); } break; case TF_show_task: // -L and -T options @@ -375,11 +388,18 @@ if(want_this_proc(&buf)){ proc_t buf2; // must still have the process allocated - while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list); + while(readtask(ptp,&buf,&buf2)){ + show_one_proc(&buf2, task_format_list); + if(buf2.nsupgid > 0 && buf2.supgid && buf.supgid!=buf2.supgid) free(buf2.supgid); + if(ptp->flags & PROC_FILLSUPGRP && buf2.nsupgid>0 && buf2.supgrp && buf.supgrp!=buf2.supgrp) + freesupgrp(&buf2); + } } if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse if(buf.environ) free((void*)*buf.environ); // ought to reuse if(buf.cgroup) free((void*)*buf.cgroup); + if(buf.nsupgid > 0 && buf.supgid) free(buf.supgid); + if((ptp->flags & PROC_FILLSUPGRP) && buf.nsupgid>0 && buf.supgrp) freesupgrp(&buf); } break; } @@ -542,6 +562,12 @@ qsort(processes, n, sizeof(proc_t*), compare_two_procs); if(forest_type) show_forest(n); else show_proc_array(ptp,n); + int i; + for (i=0; insupgid>0 && processes[i]->supgid) free(processes[i]->supgid); + if (ptp->flags & PROC_FILLSUPGRP) + for (i=0; insupgid>0 && processes[i]->supgrp) freesupgrp(processes[i]); closeproc(ptp); } --- a/ps/output.c +++ b/ps/output.c @@ -211,6 +211,32 @@ return 0; } +static int sr_supgid(const proc_t* P, const proc_t* Q){ + int i; + for (i = 0; i < INT_MAX; i++){ + if (P->nsupgid == i){ + if (Q->nsupgid == i) return 0; + else return -1; + } + if (Q->nsupgid == i) return 1; + if (P->supgid[i] != Q->supgid[i]) return P->supgid[i] - Q->supgid[i]; + } + return 0; +} + +static int sr_supgrp(const proc_t* P, const proc_t* Q){ + int i; + for (i = 0; i < INT_MAX; i++){ + if (P->nsupgid == i){ + if (Q->nsupgid == i) return 0; + else return -1; + } + if (Q->nsupgid == i) return 1; + int cmp = strncmp(P->supgrp[i],Q->supgrp[i],P_G_SZ); + if (cmp != 0) return cmp; + } + return 0; +} /***************************************************************************/ /************ Lots of format functions, starting with the NOP **************/ @@ -1062,6 +1088,24 @@ return snprintf(outbuf, COLWID, "%d", pp->fuid); } +static int pr_supgid(char *restrict const outbuf, const proc_t *restrict const pp){ + if (pp->nsupgid == 0) return snprintf(outbuf,2,"-"); + int rest = COLWID; + int i = 0; + for (i = 0; i < pp->nsupgid && rest > 5; i++) + rest-= snprintf(outbuf+COLWID-rest, rest, "%d ", pp->supgid[i]); + return COLWID-rest; +} + +static int pr_supgrp(char *restrict const outbuf, const proc_t *restrict const pp){ + if (pp->nsupgid == 0) return snprintf(outbuf,2,"-"); + int rest = COLWID; + int i = 0; + for (i = 0; i < pp->nsupgid && rest > sizeof( pp->supgrp[i] ) + 1; i++) + rest-= snprintf(outbuf+COLWID-rest, rest, "%s ", pp->supgrp[i]); + return COLWID-rest; +} + // The Open Group Base Specifications Issue 6 (IEEE Std 1003.1, 2004 Edition) // requires that user and group names print as decimal numbers if there is // not enough room in the column, so tough luck if you don't like it. @@ -1293,6 +1337,7 @@ #define USR PROC_FILLUSR /* uid_t -> user names */ #define GRP PROC_FILLGRP /* gid_t -> group names */ #define WCH PROC_FILLWCHAN /* do WCHAN lookup */ +#define SUPGRP PROC_FILLSUPGRP /* supgid -> supplementary group names */ #define CGRP PROC_FILLCGROUP /* read cgroup */ /* TODO @@ -1490,6 +1535,8 @@ {"status", "STATUS", pr_nop, sr_nop, 6, 0, DEC, AN|RIGHT}, {"stime", "STIME", pr_stime, sr_stime, 5, 0, XXX, ET|RIGHT}, /* was 6 wide */ {"suid", "SUID", pr_suid, sr_suid, 5, 0, LNx, ET|RIGHT}, +{"supgid", "SUPGID", pr_supgid, sr_supgid, 27, 0, LNX, PO|UNLIMITED}, +{"supgrp", "SUPGRP", pr_supgrp, sr_supgrp, 27, SUPGRP, LNX, PO|UNLIMITED}, {"suser", "SUSER", pr_suser, sr_suser, 8, USR, LNx, ET|USER}, {"svgid", "SVGID", pr_sgid, sr_sgid, 5, 0, XXX, ET|RIGHT}, {"svgroup", "SVGROUP", pr_sgroup, sr_sgroup, 8, GRP, LNX, ET|USER}, --- a/ps/ps.1 +++ b/ps/ps.1 @@ -1303,6 +1303,16 @@ saved user\ ID. (alias\ \fBsvuid\fR). T} +supgid SUPGID T{ +gid of supplementary groups, see +.BR getgroups (2). +T} + +supgrp SUPGRP T{ +names of supplementary groups, see +.BR getgroups (2). +T} + suser SUSER T{ saved user name. This will be the textual user\ ID, if\ it can be obtained and the field width permits,