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