Blob Blame History Raw
commit a01ee3c0b32d4c39aa83066ed61103343469527e
Author: Aristeu Rozanski <arozansk@redhat.com>
Date:   Mon Apr 8 15:03:13 2013 -0400

    procps: add support for linux namespaces
    
    Each process in Linux has a /proc/<pid>/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 <arozansk@redhat.com>

---
 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/<pid>/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 .