commit a01ee3c0b32d4c39aa83066ed61103343469527e Author: Aristeu Rozanski Date: Mon Apr 8 15:03:13 2013 -0400 procps: add support for linux namespaces Each process in Linux has a /proc//ns directory which contains symbolic links to pipes that identify which namespaces that process belongs to. This patch adds support for ps to display that information optionally. Signed-off-by: Aristeu Rozanski --- proc/libprocps.sym | 2 + proc/readproc.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ proc/readproc.h | 15 +++++++++++++ ps/output.c | 38 ++++++++++++++++++++++++++++++++++ ps/ps.1 | 24 +++++++++++++++++++++ 5 files changed, 137 insertions(+) --- procps-ng-3.3.8.orig/proc/libprocps.sym 2013-05-25 17:39:40.000000000 -0400 +++ procps-ng-3.3.8/proc/libprocps.sym 2013-09-17 16:09:45.496846630 -0400 @@ -11,6 +11,8 @@ global: escaped_copy; free_slabinfo; freeproc; + get_ns_id; + get_ns_name; get_pid_digits; get_slabinfo; getbtime; --- procps-ng-3.3.8.orig/proc/readproc.c 2013-05-25 17:39:40.000000000 -0400 +++ procps-ng-3.3.8/proc/readproc.c 2013-09-17 16:09:45.498846654 -0400 @@ -457,6 +457,51 @@ static void oomadj2proc(const char* S, p #endif /////////////////////////////////////////////////////////////////////// +static ino_t _ns2proc(unsigned pid, const char *ns) +{ + struct stat s; + char filename[40]; + + snprintf(filename, sizeof(filename), "/proc/%i/ns/%s", pid, ns); + + if (stat(filename, &s) == -1) + return 0; + + return s.st_ino; +} + +static const char *ns_names[] = { + [IPCNS] = "ipc", + [MNTNS] = "mnt", + [NETNS] = "net", + [PIDNS] = "pid", + [USERNS] = "user", + [UTSNS] = "uts", +}; + +const char *get_ns_name(int id) { + if (id >= NUM_NS) + return NULL; + return ns_names[id]; +} + +int get_ns_id(const char *name) { + int i; + + for (i = 0; i < NUM_NS; i++) + if (!strcmp(ns_names[i], name)) + return i; + return -1; +} + +static void ns2proc(proc_t *restrict P) { + int i; + + for (i = 0; i < NUM_NS; i++) + P->ns[i] = _ns2proc(P->tgid, ns_names[i]); +} +/////////////////////////////////////////////////////////////////////// + // Reads /proc/*/stat files, being careful not to trip over processes with // names like ":-) 1 2 3 4 5 6". @@ -757,6 +802,7 @@ static struct utlbuf_s ub = { NULL, static struct stat sb; // stat() buffer char *restrict const path = PT->path; unsigned flags = PT->flags; + int i; if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */ goto next_proc; @@ -844,6 +890,12 @@ p->wchan = (KLONG)~0ull; } #endif + if (unlikely(flags & PROC_FILLNS)) // read /proc/#/ns/* + ns2proc(p); + else + for (i = 0; i < NUM_NS; i++) + p->ns[i] = 0; + return p; next_proc: return NULL; @@ -862,6 +914,7 @@ static proc_t* simple_readtask(PROCTAB * static struct utlbuf_s ub = { NULL, 0 }; // buf for stat,statm,status static struct stat sb; // stat() buffer unsigned flags = PT->flags; + int i; if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */ goto next_task; @@ -974,6 +1027,11 @@ status2proc(ub.buf, t, 0); oomadj2proc(ub.buf, t); } #endif + if (unlikely(flags & PROC_FILLNS)) + ns2proc(t); + else + for (i = 0; i < NUM_NS; i++) + t->ns[i] = 0; return t; next_task: --- procps-ng-3.3.8.orig/proc/readproc.h 2013-05-25 17:39:40.000000000 -0400 +++ procps-ng-3.3.8/proc/readproc.h 2013-09-17 16:09:45.499846666 -0400 @@ -31,6 +31,18 @@ EXTERN_C_BEGIN // neither tgid nor tid seemed correct. (in other words, FIXME) #define XXXID tid +#define NUM_NS 6 +enum ns_type { + IPCNS = 0, + MNTNS, + NETNS, + PIDNS, + USERNS, + UTSNS +}; +extern const char *get_ns_name(int id); +extern int get_ns_id(const char *name); + // Basic data structure which holds all information we can get about a process. // (unless otherwise specified, fields are read from /proc/#/stat) // @@ -157,6 +169,8 @@ nlwp, // stat,status number of thr oom_score, // oom_score (badness for OOM killer) oom_adj; // oom_adj (adjustment to OOM score) #endif + ino_t + ns[NUM_NS]; // ns/* inode number of /proc//ns/* } proc_t; // PROCTAB: data structure holding the persistent information readproc needs @@ -266,6 +280,7 @@ #define PROC_FILLARG 0x0100 // a #define PROC_FILLCGROUP 0x0200 // alloc and fill in `cgroup` #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 #define PROC_LOOSE_TASKS 0x2000 // treat threads as if they were processes --- procps-ng-3.3.8.orig/ps/output.c 2013-09-17 16:08:53.000000000 -0400 +++ procps-ng-3.3.8/ps/output.c 2013-09-17 16:10:41.087532129 -0400 @@ -139,6 +139,13 @@ static int sr_ ## NAME (const proc_t* P, return 0; \ } +#define CMP_NS(NAME, ID) \ +static int sr_ ## NAME (const proc_t* P, const proc_t* Q) { \ + if (P->ns[ID] < Q->ns[ID]) return -1; \ + if (P->ns[ID] > Q->ns[ID]) return 1; \ + return 0; \ +} + CMP_INT(rtprio) CMP_SMALL(sched) CMP_INT(cutime) @@ -216,6 +223,13 @@ CMP_SMALL(state) CMP_COOKED_TIME(time) CMP_COOKED_TIME(etime) +CMP_NS(ipcns, IPCNS); +CMP_NS(mntns, MNTNS); +CMP_NS(netns, NETNS); +CMP_NS(pidns, PIDNS); +CMP_NS(userns, USERNS); +CMP_NS(utsns, UTSNS); + /* approximation to: kB of address space that could end up in swap */ static int sr_swapable(const proc_t* P, const proc_t* Q) { unsigned long p_swapable = P->vm_data + P->vm_stack; @@ -1279,6 +1293,23 @@ outbuf[1] = '\0'; } #endif + +/************************ Linux namespaces ******************************/ + +#define _pr_ns(NAME, ID)\ +static int pr_##NAME(char *restrict const outbuf, const proc_t *restrict const pp) {\ + if (pp->ns[ID])\ + return snprintf(outbuf, COLWID, "%li", pp->ns[ID]);\ + else\ + return snprintf(outbuf, COLWID, "-");\ +} +_pr_ns(ipcns, IPCNS); +_pr_ns(mntns, MNTNS); +_pr_ns(netns, NETNS); +_pr_ns(pidns, PIDNS); +_pr_ns(userns, USERNS); +_pr_ns(utsns, UTSNS); + /****************** FLASK & seLinux security stuff **********************/ // move the bulk of this to libproc sometime @@ -1439,6 +1470,7 @@ static const char *const vals[] = {"tt #define USR PROC_FILLUSR /* uid_t -> user names */ #define GRP PROC_FILLGRP /* gid_t -> group names */ #define WCH PROC_FILLWCHAN /* do WCHAN lookup */ +#define NS PROC_FILLNS /* read namespace information */ #define SGRP PROC_FILLSTATUS | PROC_FILLSUPGRP /* supgid -> supgrp (names) */ #define CGRP PROC_FILLCGROUP | PROC_EDITCGRPCVT /* read cgroup */ @@ -1527,6 +1559,7 @@ {"ignored", "IGNORED", pr_sigignore,sr {"inblk", "INBLK", pr_nop, sr_nop, 5, 0, BSD, AN|RIGHT}, /*inblock*/ {"inblock", "INBLK", pr_nop, sr_nop, 5, 0, DEC, AN|RIGHT}, /*inblk*/ {"intpri", "PRI", pr_opri, sr_priority, 3, 0, HPU, TO|RIGHT}, +{"ipcns", "IPCNS", pr_ipcns, sr_ipcns, 10, NS, LNX, ET|RIGHT}, {"jid", "JID", pr_nop, sr_nop, 1, 0, SGI, PO|RIGHT}, {"jobc", "JOBC", pr_nop, sr_nop, 4, 0, XXX, AN|RIGHT}, {"ktrace", "KTRACE", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT}, @@ -1559,9 +1592,11 @@ {"maj_flt", "MAJFL", pr_majflt, sr {"majflt", "MAJFLT", pr_majflt, sr_maj_flt, 6, 0, XXX, AN|RIGHT}, {"min_flt", "MINFL", pr_minflt, sr_min_flt, 6, 0, LNX, AN|RIGHT}, {"minflt", "MINFLT", pr_minflt, sr_min_flt, 6, 0, XXX, AN|RIGHT}, +{"mntns", "MNTNS", pr_mntns, sr_mntns, 10, NS, LNX, ET|RIGHT}, {"msgrcv", "MSGRCV", pr_nop, sr_nop, 6, 0, XXX, AN|RIGHT}, {"msgsnd", "MSGSND", pr_nop, sr_nop, 6, 0, XXX, AN|RIGHT}, {"mwchan", "MWCHAN", pr_nop, sr_nop, 6, WCH, BSD, TO|WCHAN}, /* mutex (FreeBSD) */ +{"netns", "NETNS", pr_netns, sr_netns, 10, NS, LNX, ET|RIGHT}, {"ni", "NI", pr_nice, sr_nice, 3, 0, BSD, TO|RIGHT}, /*nice*/ {"nice", "NI", pr_nice, sr_nice, 3, 0, U98, TO|RIGHT}, /*ni*/ {"nivcsw", "IVCSW", pr_nop, sr_nop, 5, 0, XXX, AN|RIGHT}, @@ -1586,6 +1621,7 @@ {"pending", "PENDING", pr_sig, sr {"pgid", "PGID", pr_pgid, sr_pgrp, 5, 0, U98, PO|PIDMAX|RIGHT}, {"pgrp", "PGRP", pr_pgid, sr_pgrp, 5, 0, LNX, PO|PIDMAX|RIGHT}, {"pid", "PID", pr_procs, sr_procs, 5, 0, U98, PO|PIDMAX|RIGHT}, +{"pidns", "PIDNS", pr_pidns, sr_pidns, 10, NS, LNX, ET|RIGHT}, {"pmem", "%MEM", pr_pmem, sr_rss, 4, 0, XXX, PO|RIGHT}, /*%mem*/ {"poip", "-", pr_nop, sr_nop, 1, 0, BSD, AN|RIGHT}, {"policy", "POL", pr_class, sr_sched, 3, 0, DEC, TO|LEFT}, @@ -1693,6 +1729,7 @@ {"unit", "UNIT", pr_sd_unit, sr {"upr", "UPR", pr_nop, sr_nop, 3, 0, BSD, TO|RIGHT}, /*usrpri*/ {"uprocp", "UPROCP", pr_nop, sr_nop, 8, 0, BSD, AN|RIGHT}, {"user", "USER", pr_euser, sr_euser, 8, USR, U98, ET|USER}, /* BSD n forces this to UID */ +{"userns", "USERNS", pr_userns, sr_userns, 10, NS, LNX, ET|RIGHT}, {"usertime", "USER", pr_nop, sr_nop, 4, 0, DEC, ET|RIGHT}, {"usrpri", "UPR", pr_nop, sr_nop, 3, 0, DEC, TO|RIGHT}, /*upr*/ {"util", "C", pr_c, sr_pcpu, 2, 0, SGI, ET|RIGHT}, // not sure about "C" @@ -1700,6 +1737,7 @@ {"utime", "UTIME", pr_nop, sr #ifdef WITH_SYSTEMD {"uunit", "UUNIT", pr_sd_uunit, sr_nop, 31, 0, LNX, ET|LEFT}, #endif +{"utsns", "UTSNS", pr_utsns, sr_utsns, 10, NS, LNX, ET|RIGHT}, {"vm_data", "DATA", pr_nop, sr_vm_data, 5, 0, LNx, PO|RIGHT}, {"vm_exe", "EXE", pr_nop, sr_vm_exe, 5, 0, LNx, PO|RIGHT}, {"vm_lib", "LIB", pr_nop, sr_vm_lib, 5, 0, LNx, PO|RIGHT}, --- procps-ng-3.3.8.orig/ps/ps.1 2013-05-25 17:39:40.000000000 -0400 +++ procps-ng-3.3.8/ps/ps.1 2013-09-17 16:11:12.942925254 -0400 @@ -1299,6 +1299,10 @@ format is displayed. (alias .BR sig_ignore , \ sigignore ). T} +ipcns IPCNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + label LABEL T{ security label, most commonly used for SELinux context data. This is for the @@ -1335,6 +1339,14 @@ min_flt MINFLT T{ The number of minor page faults that have occurred with this process. T} +mntns MNTNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + +netns NETNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + ni NI T{ nice value. This ranges from 19 (nicest) to \-20 (not nice to others), see @@ -1403,6 +1415,10 @@ a number representing the process ID (al .BR tgid ). T} +pidns PIDNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + pmem %MEM T{ see .BR %mem . @@ -1739,6 +1755,14 @@ uunit UUNIT T{ displays systemd user unit which a process belongs to. T} +userns USERNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + +utsns UTSNS T{ +Unique inode number describing the namespace the process belongs to. See namespaces(7). +T} + vsize VSZ T{ see .BR vsz .