Blame SOURCES/pstree-introduce-support-for-namespaces.patch

f10d51
From c9f6f3e60d1770a95eb491dd503fdbe881ee8740 Mon Sep 17 00:00:00 2001
f10d51
From: Aristeu Rozanski <arozansk@redhat.com>
f10d51
Date: Wed, 24 Apr 2013 15:32:35 -0400
f10d51
Subject: [PATCH 1/3] pstree: introduce support for namespaces
f10d51
f10d51
Options -N and --ns-sort were added which require one of the namespaces:
f10d51
ipc, mnt, net, pid, user, uts
f10d51
and will show separated trees per namespace
f10d51
f10d51
Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
f10d51
Signed-off-by: Craig Small <csmall@enc.com.au>
f10d51
---
f10d51
 doc/pstree.1 |    6 ++
f10d51
 src/pstree.c |  170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
f10d51
 2 files changed, 173 insertions(+), 3 deletions(-)
f10d51
f10d51
--- psmisc-22.20.orig/doc/pstree.1	2012-09-19 06:54:03.000000000 -0400
f10d51
+++ psmisc-22.20/doc/pstree.1	2013-09-17 16:26:00.210118465 -0400
f10d51
@@ -18,6 +18,7 @@ pstree \- display a tree of processes
f10d51
 .RB [ \-g  ] \ \-\-show\-pgids ]
f10d51
 .RB [ \-l  , \ \-\-long ]
f10d51
 .RB [ \-n  , \ \-\-numeric\-sort ]
f10d51
+.RB [ \-N  , \ \-\-ns\-sort \fIns\fB
f10d51
 .RB [ \-p  , \ \-\-show\-pids ]
f10d51
 .RB [ \-s  , \ \-\-show\-parents ]
f10d51
 .RB [ \-u  , \ \-\-uid\-changes ]
f10d51
@@ -121,6 +122,11 @@ unknown.
f10d51
 .IP \fB\-n\fP
f10d51
 Sort processes with the same ancestor by PID instead of by name. 
f10d51
 (Numeric sort.)
f10d51
+.IP \fB\-N\fP
f10d51
+Show individual trees for each namespace of the type specified.  The
f10d51
+available types are: ipc, mnt, net, pid, user, uts.  Regular users don't
f10d51
+have access to other users' processes information, so the output will be
f10d51
+limited.
f10d51
 .IP \fB\-p\fP
f10d51
 Show PIDs.  PIDs are shown as decimal numbers in parentheses after each
f10d51
 process name.
f10d51
--- psmisc-22.20.orig/src/pstree.c	2013-09-17 16:25:01.000000000 -0400
f10d51
+++ psmisc-22.20/src/pstree.c	2013-09-17 16:27:12.356037690 -0400
f10d51
@@ -74,6 +74,8 @@ #define VT_END        "\033(B"        /*
f10d51
 #define VT_UR        "m"
f10d51
 #define        VT_HD        "w"
f10d51
 
f10d51
+#define NUM_NS 6
f10d51
+
f10d51
 typedef struct _proc {
f10d51
     char comm[COMM_LEN + 2 + 1]; /* add another 2 for thread brackets */
f10d51
     char **argv;                /* only used : argv[0] is 1st arg; undef if argc < 1 */
f10d51
@@ -84,6 +86,7 @@     char **argv;                /* only 
f10d51
 #ifdef WITH_SELINUX
f10d51
     security_context_t scontext;
f10d51
 #endif                                /*WITH_SELINUX */
f10d51
+    ino_t ns[NUM_NS];
f10d51
     char flags;
f10d51
     struct _child *children;
f10d51
     struct _proc *parent;
f10d51
@@ -140,6 +143,133 @@ static char last_char = 0;
f10d51
 static int dumped = 0;                /* used by dump_by_user */
f10d51
 static int charlen = 0;                /* length of character */
f10d51
 
f10d51
+enum ns_type {
f10d51
+    IPCNS = 0,
f10d51
+    MNTNS,
f10d51
+    NETNS,
f10d51
+    PIDNS,
f10d51
+    USERNS,
f10d51
+    UTSNS
f10d51
+};
f10d51
+struct ns_entry;
f10d51
+struct ns_entry {
f10d51
+    ino_t number;
f10d51
+    CHILD *children;
f10d51
+    struct ns_entry *next;
f10d51
+};
f10d51
+
f10d51
+static const char *ns_names[] = {
f10d51
+    [IPCNS] = "ipc",
f10d51
+    [MNTNS] = "mnt",
f10d51
+    [NETNS] = "net",
f10d51
+    [PIDNS] = "pid",
f10d51
+    [USERNS] = "user",
f10d51
+    [UTSNS] = "uts",
f10d51
+};
f10d51
+
f10d51
+const char *get_ns_name(int id) {
f10d51
+    if (id >= NUM_NS)
f10d51
+        return NULL;
f10d51
+    return ns_names[id];
f10d51
+}
f10d51
+
f10d51
+static int get_ns_id(const char *name) {
f10d51
+    int i;
f10d51
+
f10d51
+    for (i = 0; i < NUM_NS; i++)
f10d51
+        if (!strcmp(ns_names[i], name))
f10d51
+            return i;
f10d51
+    return -1;
f10d51
+}
f10d51
+
f10d51
+static int verify_ns(int id)
f10d51
+{
f10d51
+    char filename[50];
f10d51
+    struct stat s;
f10d51
+
f10d51
+    snprintf(filename, 50, "/proc/%i/ns/%s", getpid(), get_ns_name(id));
f10d51
+
f10d51
+    return stat(filename, &s);
f10d51
+}
f10d51
+
f10d51
+static inline void new_proc_ns(PROC *ns_task)
f10d51
+{
f10d51
+    struct stat st;
f10d51
+    char buff[50];
f10d51
+    pid_t pid = ns_task->pid;
f10d51
+    int i;
f10d51
+
f10d51
+    for (i = 0; i < NUM_NS; i++) {
f10d51
+        snprintf(buff, sizeof(buff), "/proc/%i/ns/%s", pid,
f10d51
+                 get_ns_name(i));
f10d51
+        if (stat(buff, &st)) {
f10d51
+            ns_task->ns[i] = 0;
f10d51
+            continue;
f10d51
+        }
f10d51
+        ns_task->ns[i] = st.st_ino;
f10d51
+    }
f10d51
+}
f10d51
+
f10d51
+static void find_ns_and_add(struct ns_entry **root, PROC *r, enum ns_type id)
f10d51
+{
f10d51
+    struct ns_entry *ptr, *last = NULL;
f10d51
+    CHILD **c;
f10d51
+
f10d51
+    for (ptr = *root; ptr; ptr = ptr->next) {
f10d51
+        if (ptr->number == r->ns[id])
f10d51
+            break;
f10d51
+        last = ptr;
f10d51
+    }
f10d51
+
f10d51
+    if (!ptr) {
f10d51
+        ptr = malloc(sizeof(*ptr));
f10d51
+        memset(ptr, 0, sizeof(*ptr));
f10d51
+        ptr->number = r->ns[id];
f10d51
+        if (*root == NULL)
f10d51
+            *root = ptr;
f10d51
+        else
f10d51
+            last->next = ptr;
f10d51
+    }
f10d51
+
f10d51
+    /* move the child to under the namespace's umbrella */
f10d51
+    for (c = &ptr->children; *c; c = &(*c)->next)
f10d51
+        ;
f10d51
+    *c = malloc(sizeof(CHILD));
f10d51
+    (*c)->child = r;
f10d51
+    (*c)->next = NULL;
f10d51
+
f10d51
+    /* detaching from parent */
f10d51
+    if (r->parent) {
f10d51
+        for (c = &r->parent->children; *c; c = &(*c)->next) {
f10d51
+            if ((*c)->child == r) {
f10d51
+                *c = (*c)->next;
f10d51
+                break;
f10d51
+            }
f10d51
+        }
f10d51
+        r->parent = NULL;
f10d51
+    }
f10d51
+
f10d51
+}
f10d51
+
f10d51
+static PROC *find_proc(pid_t pid);
f10d51
+static void sort_by_namespace(PROC *r, enum ns_type id, struct ns_entry **root)
f10d51
+{
f10d51
+    CHILD *walk;
f10d51
+
f10d51
+    /* first run, find the first process */
f10d51
+    if (!r) {
f10d51
+        r = find_proc(1);
f10d51
+        if (!r)
f10d51
+            return;
f10d51
+    }
f10d51
+
f10d51
+    if (r->parent == NULL || r->parent->ns[id] != r->ns[id])
f10d51
+        find_ns_and_add(root, r, id);
f10d51
+
f10d51
+    for (walk = r->children; walk; walk = walk->next)
f10d51
+        sort_by_namespace(walk->child, id, root);
f10d51
+}
f10d51
+
f10d51
 #ifdef WITH_SELINUX
f10d51
 static void fix_orphans(security_context_t scontext);
f10d51
 #else
f10d51
@@ -290,6 +420,7 @@     new->argc = 0;
f10d51
     new->children = NULL;
f10d51
     new->parent = NULL;
f10d51
     new->next = list;
f10d51
+    new_proc_ns(new);
f10d51
     return list = new;
f10d51
 }
f10d51
 
f10d51
@@ -624,6 +755,20 @@         dump_tree(current, 0, 1, 1, 1, u
f10d51
         dump_by_user(walk->child, uid);
f10d51
 }
f10d51
 
f10d51
+static void dump_by_namespace(struct ns_entry *root)
f10d51
+{
f10d51
+    struct ns_entry *ptr = root;
f10d51
+    CHILD *c;
f10d51
+    char buff[14];
f10d51
+
f10d51
+    for ( ; ptr; ptr = ptr->next) {
f10d51
+        snprintf(buff, sizeof(buff), "[%li]\n", ptr->number);
f10d51
+        out_string(buff);
f10d51
+        for (c = ptr->children; c; c = c->next)
f10d51
+            dump_tree(c->child, 0, 1, 1, 1, 0, 0);
f10d51
+    }
f10d51
+}
f10d51
+
f10d51
 static void trim_tree_by_parent(PROC * current)
f10d51
 {
f10d51
   if (!current)
f10d51
@@ -853,6 +998,8 @@ static void usage(void)
f10d51
              "  -G, --vt100         use VT100 line drawing characters\n"
f10d51
              "  -l, --long          don't truncate long lines\n"
f10d51
              "  -n, --numeric-sort  sort output by PID\n"
f10d51
+             "  -N type,\n"
f10d51
+             "  --ns-sort=type      sort by namespace type (ipc, mnt, net, pid, user, uts)\n"
f10d51
              "  -p, --show-pids     show PIDs; implies -c\n"
f10d51
              "  -s, --show-parents  show parents of the selected process\n"
f10d51
              "  -u, --uid-changes   show uid transitions\n"
f10d51
@@ -886,11 +1033,13 @@ int main(int argc, char **argv)
f10d51
 {
f10d51
     PROC *current;
f10d51
     struct winsize winsz;
f10d51
+    struct ns_entry *nsroot = NULL;
f10d51
     const struct passwd *pw;
f10d51
     pid_t pid, highlight;
f10d51
     char termcap_area[1024];
f10d51
     char *termname, *endptr;
f10d51
     int c, pid_set;
f10d51
+    enum ns_type nsid = -1;
f10d51
 
f10d51
     struct option options[] = {
f10d51
         {"arguments", 0, NULL, 'a'},
f10d51
@@ -901,6 +1050,7 @@         {"highlight-all", 0, NULL, 'h'},
f10d51
         {"highlight-pid", 1, NULL, 'H'},
f10d51
         {"long", 0, NULL, 'l'},
f10d51
         {"numeric-sort", 0, NULL, 'n'},
f10d51
+        {"ns-sort", 1, NULL, 'N' },
f10d51
         {"show-pids", 0, NULL, 'p'},
f10d51
         {"show-pgids", 0, NULL, 'g'},
f10d51
         {"show-parents", 0, NULL, 's'},
f10d51
@@ -956,11 +1106,11 @@         /* problems with VT100 on some t
f10d51
 
f10d51
 #ifdef WITH_SELINUX
f10d51
     while ((c =
f10d51
-            getopt_long(argc, argv, "aAcGhH:npglsuUVZ", options,
f10d51
+            getopt_long(argc, argv, "aAcGhH:nN:pglsuUVZ", options,
f10d51
                         NULL)) != -1)
f10d51
 #else                                /*WITH_SELINUX */
f10d51
     while ((c =
f10d51
-            getopt_long(argc, argv, "aAcGhH:npglsuUV", options, NULL)) != -1)
f10d51
+            getopt_long(argc, argv, "aAcGhH:nN:pglsuUV", options, NULL)) != -1)
f10d51
 #endif                                /*WITH_SELINUX */
f10d51
         switch (c) {
f10d51
         case 'a':
f10d51
@@ -1002,6 +1152,17 @@             trunc = 0;
f10d51
         case 'n':
f10d51
             by_pid = 1;
f10d51
             break;
f10d51
+        case 'N':
f10d51
+            nsid = get_ns_id(optarg);
f10d51
+            if (nsid == -1)
f10d51
+                 usage();
f10d51
+            if (verify_ns(nsid)) {
f10d51
+                 fprintf(stderr,
f10d51
+                         _("procfs file for %s namespace not available\n"),
f10d51
+                         optarg);
f10d51
+                 return 1;
f10d51
+            }
f10d51
+            break;
f10d51
         case 'p':
f10d51
             pids = 1;
f10d51
             compact = 0;
f10d51
@@ -1059,7 +1220,10 @@             if (endptr[0] != '\0')
f10d51
       pid = ROOT_PID;
f10d51
     }
f10d51
 
f10d51
-    if (!pw)
f10d51
+    if (nsid != -1) {
f10d51
+        sort_by_namespace(NULL, nsid, &nsroot);
f10d51
+        dump_by_namespace(nsroot);
f10d51
+    } else if (!pw)
f10d51
         dump_tree(find_proc(pid), 0, 1, 1, 1, 0, 0);
f10d51
     else {
f10d51
         dump_by_user(find_proc(ROOT_PID), pw->pw_uid);