From e80233be0edb4fbbe60a2e0c3db5069db12e2cb3 Mon Sep 17 00:00:00 2001 From: Jaromir Capik Date: Tue, 8 Oct 2013 17:02:27 +0200 Subject: [PATCH] - Introducing namespaces support (#1016259) --- psmisc.spec | 9 +- ...uce-namespace-transition-information.patch | 121 +++++++ pstree-introduce-support-for-namespaces.patch | 295 ++++++++++++++++++ 3 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 pstree-introduce-namespace-transition-information.patch create mode 100644 pstree-introduce-support-for-namespaces.patch diff --git a/psmisc.spec b/psmisc.spec index 2e06010..47e7929 100644 --- a/psmisc.spec +++ b/psmisc.spec @@ -1,7 +1,7 @@ Summary: Utilities for managing processes on your system Name: psmisc Version: 22.20 -Release: 3%{?dist} +Release: 4%{?dist} License: GPLv2+ Group: Applications/System URL: http://sourceforge.net/projects/psmisc @@ -16,6 +16,8 @@ Patch2: psmisc-22.20-fix-selinux-in-pstree.patch Patch3: psmisc-22.20-RH-man-page-scan.patch +Patch4: pstree-introduce-support-for-namespaces.patch +Patch5: pstree-introduce-namespace-transition-information.patch BuildRequires: libselinux-devel BuildRequires: gettext @@ -36,6 +38,8 @@ of processes that are using specified files or filesystems. %patch2 -p1 %patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build %configure --prefix=%{_prefix} --enable-selinux @@ -66,6 +70,9 @@ mv $RPM_BUILD_ROOT%{_bindir}/fuser $RPM_BUILD_ROOT/sbin %doc AUTHORS ChangeLog COPYING README %changelog +* Tue Sep 17 2013 Aristeu Rozanski - 22.20-4 +- Introducing namespaces support (#1016259) + * Tue Jul 30 2013 Jaromir Capik - 22.20-3 - RH man page scan (#948524) diff --git a/pstree-introduce-namespace-transition-information.patch b/pstree-introduce-namespace-transition-information.patch new file mode 100644 index 0000000..773985d --- /dev/null +++ b/pstree-introduce-namespace-transition-information.patch @@ -0,0 +1,121 @@ +From 29ac10530c97631d76aa34b2d2ed018ded60d6bf Mon Sep 17 00:00:00 2001 +From: Aristeu Rozanski +Date: Thu, 25 Apr 2013 11:35:15 -0400 +Subject: [PATCH 2/3] pstree: introduce namespace transition information + +This patch adds a new option (-S, --ns-change) that will show +when a namespace was changed compared to parent's. + +Signed-off-by: Aristeu Rozanski +Signed-off-by: Craig Small +--- + doc/pstree.1 | 4 ++++ + src/pstree.c | 27 ++++++++++++++++++++++++--- + 2 files changed, 28 insertions(+), 3 deletions(-) + +--- psmisc-22.20.orig/doc/pstree.1 2013-09-17 16:26:00.000000000 -0400 ++++ psmisc-22.20/doc/pstree.1 2013-09-17 16:27:22.510167111 -0400 +@@ -21,6 +21,7 @@ pstree \- display a tree of processes + .RB [ \-N , \ \-\-ns\-sort \fIns\fB + .RB [ \-p , \ \-\-show\-pids ] + .RB [ \-s , \ \-\-show\-parents ] ++.RB [ \-S , \ \-\-ns-changes ] + .RB [ \-u , \ \-\-uid\-changes ] + .RB [ \-Z , \ \-\-security\-context ] + .RB [ \-A , \ \-\-ascii , \ \-G , \ \-\-vt100 , \ \-U , \ \-\-unicode ] +@@ -134,6 +135,9 @@ process name. + implicitly disables compaction. + .IP \fB\-s\fP + Show parent processes of the specified process. ++.IP \fB\-S\fP ++Show namespaces transitions. Like \-N, the output is limited when running ++as a regular user. + .IP \fB\-u\fP + Show uid transitions. Whenever the uid of a process differs from the + uid of its parent, the new uid is shown in parentheses after the +--- psmisc-22.20.orig/src/pstree.c 2013-09-17 16:27:12.000000000 -0400 ++++ psmisc-22.20/src/pstree.c 2013-09-17 16:28:04.156698164 -0400 +@@ -133,7 +133,7 @@ static int *width = NULL; + static int *more = NULL; + + static int print_args = 0, compact = 1, user_change = 0, pids = 0, pgids = 0, +- show_parents = 0, by_pid = 0, trunc = 1, wait_end = 0; ++ show_parents = 0, by_pid = 0, trunc = 1, wait_end = 0, ns_change = 0; + #ifdef WITH_SELINUX + static int show_scontext = 0; + #endif /*WITH_SELINUX */ +@@ -545,11 +545,17 @@ if (pid != 0) { + static int tree_equal(const PROC * a, const PROC * b) + { + const CHILD *walk_a, *walk_b; ++ int i; + + if (strcmp(a->comm, b->comm)) + return 0; + if (user_change && a->uid != b->uid) + return 0; ++ if (ns_change) { ++ for (i = 0; i < NUM_NS; i++) ++ if (a->ns[i] != b->ns[i]) ++ return 0; ++ } + for (walk_a = a->children, walk_b = b->children; walk_a && walk_b; + walk_a = walk_a->next, walk_b = walk_b->next) + if (!tree_equal(walk_a->child, walk_b->child)) +@@ -630,6 +636,16 @@ if (swapped && current->argc < 0) + else + (void) out_int(current->uid); + } ++ if (ns_change && current->parent) { ++ for (i = 0; i < NUM_NS; i++) { ++ if (current->ns[i] == 0 || current->parent->ns[i] == 0) ++ continue; ++ if (current->ns[i] != current->parent->ns[i]) { ++ out_char(info++ ? ',' : '('); ++ out_string(get_ns_name(i)); ++ } ++ } ++ } + #ifdef WITH_SELINUX + if (show_scontext) { + out_char(info++ ? ',' : '('); +@@ -1002,6 +1018,7 @@ " -G, --vt100 use + " --ns-sort=type sort by namespace type (ipc, mnt, net, pid, user, uts)\n" + " -p, --show-pids show PIDs; implies -c\n" + " -s, --show-parents show parents of the selected process\n" ++ " -S, --ns-changes show namespace transitions\n" + " -u, --uid-changes show uid transitions\n" + " -U, --unicode use UTF-8 (Unicode) line drawing characters\n" + " -V, --version display version information\n")); +@@ -1054,6 +1071,7 @@ {"numeric-sort", 0, NULL, 'n'}, + {"show-pids", 0, NULL, 'p'}, + {"show-pgids", 0, NULL, 'g'}, + {"show-parents", 0, NULL, 's'}, ++ {"ns-changes", 0, NULL, 'S' }, + {"uid-changes", 0, NULL, 'u'}, + {"unicode", 0, NULL, 'U'}, + {"version", 0, NULL, 'V'}, +@@ -1106,11 +1124,11 @@ /* problems with VT100 on some t + + #ifdef WITH_SELINUX + while ((c = +- getopt_long(argc, argv, "aAcGhH:nN:pglsuUVZ", options, ++ getopt_long(argc, argv, "aAcGhH:nN:pglsSuUVZ", options, + NULL)) != -1) + #else /*WITH_SELINUX */ + while ((c = +- getopt_long(argc, argv, "aAcGhH:nN:pglsuUV", options, NULL)) != -1) ++ getopt_long(argc, argv, "aAcGhH:nN:pglsSuUV", options, NULL)) != -1) + #endif /*WITH_SELINUX */ + switch (c) { + case 'a': +@@ -1174,6 +1192,9 @@ compact = 0; + case 's': + show_parents = 1; + break; ++ case 'S': ++ ns_change = 1; ++ break; + case 'u': + user_change = 1; + break; diff --git a/pstree-introduce-support-for-namespaces.patch b/pstree-introduce-support-for-namespaces.patch new file mode 100644 index 0000000..f327ac7 --- /dev/null +++ b/pstree-introduce-support-for-namespaces.patch @@ -0,0 +1,295 @@ +From c9f6f3e60d1770a95eb491dd503fdbe881ee8740 Mon Sep 17 00:00:00 2001 +From: Aristeu Rozanski +Date: Wed, 24 Apr 2013 15:32:35 -0400 +Subject: [PATCH 1/3] pstree: introduce support for namespaces + +Options -N and --ns-sort were added which require one of the namespaces: +ipc, mnt, net, pid, user, uts +and will show separated trees per namespace + +Signed-off-by: Aristeu Rozanski +Signed-off-by: Craig Small +--- + doc/pstree.1 | 6 ++ + src/pstree.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 173 insertions(+), 3 deletions(-) + +--- psmisc-22.20.orig/doc/pstree.1 2012-09-19 06:54:03.000000000 -0400 ++++ psmisc-22.20/doc/pstree.1 2013-09-17 16:26:00.210118465 -0400 +@@ -18,6 +18,7 @@ pstree \- display a tree of processes + .RB [ \-g ] \ \-\-show\-pgids ] + .RB [ \-l , \ \-\-long ] + .RB [ \-n , \ \-\-numeric\-sort ] ++.RB [ \-N , \ \-\-ns\-sort \fIns\fB + .RB [ \-p , \ \-\-show\-pids ] + .RB [ \-s , \ \-\-show\-parents ] + .RB [ \-u , \ \-\-uid\-changes ] +@@ -121,6 +122,11 @@ unknown. + .IP \fB\-n\fP + Sort processes with the same ancestor by PID instead of by name. + (Numeric sort.) ++.IP \fB\-N\fP ++Show individual trees for each namespace of the type specified. The ++available types are: ipc, mnt, net, pid, user, uts. Regular users don't ++have access to other users' processes information, so the output will be ++limited. + .IP \fB\-p\fP + Show PIDs. PIDs are shown as decimal numbers in parentheses after each + process name. +--- psmisc-22.20.orig/src/pstree.c 2013-09-17 16:25:01.000000000 -0400 ++++ psmisc-22.20/src/pstree.c 2013-09-17 16:27:12.356037690 -0400 +@@ -74,6 +74,8 @@ #define VT_END "\033(B" /* + #define VT_UR "m" + #define VT_HD "w" + ++#define NUM_NS 6 ++ + typedef struct _proc { + char comm[COMM_LEN + 2 + 1]; /* add another 2 for thread brackets */ + char **argv; /* only used : argv[0] is 1st arg; undef if argc < 1 */ +@@ -84,6 +86,7 @@ char **argv; /* only + #ifdef WITH_SELINUX + security_context_t scontext; + #endif /*WITH_SELINUX */ ++ ino_t ns[NUM_NS]; + char flags; + struct _child *children; + struct _proc *parent; +@@ -140,6 +143,133 @@ static char last_char = 0; + static int dumped = 0; /* used by dump_by_user */ + static int charlen = 0; /* length of character */ + ++enum ns_type { ++ IPCNS = 0, ++ MNTNS, ++ NETNS, ++ PIDNS, ++ USERNS, ++ UTSNS ++}; ++struct ns_entry; ++struct ns_entry { ++ ino_t number; ++ CHILD *children; ++ struct ns_entry *next; ++}; ++ ++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]; ++} ++ ++static 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 int verify_ns(int id) ++{ ++ char filename[50]; ++ struct stat s; ++ ++ snprintf(filename, 50, "/proc/%i/ns/%s", getpid(), get_ns_name(id)); ++ ++ return stat(filename, &s); ++} ++ ++static inline void new_proc_ns(PROC *ns_task) ++{ ++ struct stat st; ++ char buff[50]; ++ pid_t pid = ns_task->pid; ++ int i; ++ ++ for (i = 0; i < NUM_NS; i++) { ++ snprintf(buff, sizeof(buff), "/proc/%i/ns/%s", pid, ++ get_ns_name(i)); ++ if (stat(buff, &st)) { ++ ns_task->ns[i] = 0; ++ continue; ++ } ++ ns_task->ns[i] = st.st_ino; ++ } ++} ++ ++static void find_ns_and_add(struct ns_entry **root, PROC *r, enum ns_type id) ++{ ++ struct ns_entry *ptr, *last = NULL; ++ CHILD **c; ++ ++ for (ptr = *root; ptr; ptr = ptr->next) { ++ if (ptr->number == r->ns[id]) ++ break; ++ last = ptr; ++ } ++ ++ if (!ptr) { ++ ptr = malloc(sizeof(*ptr)); ++ memset(ptr, 0, sizeof(*ptr)); ++ ptr->number = r->ns[id]; ++ if (*root == NULL) ++ *root = ptr; ++ else ++ last->next = ptr; ++ } ++ ++ /* move the child to under the namespace's umbrella */ ++ for (c = &ptr->children; *c; c = &(*c)->next) ++ ; ++ *c = malloc(sizeof(CHILD)); ++ (*c)->child = r; ++ (*c)->next = NULL; ++ ++ /* detaching from parent */ ++ if (r->parent) { ++ for (c = &r->parent->children; *c; c = &(*c)->next) { ++ if ((*c)->child == r) { ++ *c = (*c)->next; ++ break; ++ } ++ } ++ r->parent = NULL; ++ } ++ ++} ++ ++static PROC *find_proc(pid_t pid); ++static void sort_by_namespace(PROC *r, enum ns_type id, struct ns_entry **root) ++{ ++ CHILD *walk; ++ ++ /* first run, find the first process */ ++ if (!r) { ++ r = find_proc(1); ++ if (!r) ++ return; ++ } ++ ++ if (r->parent == NULL || r->parent->ns[id] != r->ns[id]) ++ find_ns_and_add(root, r, id); ++ ++ for (walk = r->children; walk; walk = walk->next) ++ sort_by_namespace(walk->child, id, root); ++} ++ + #ifdef WITH_SELINUX + static void fix_orphans(security_context_t scontext); + #else +@@ -290,6 +420,7 @@ new->argc = 0; + new->children = NULL; + new->parent = NULL; + new->next = list; ++ new_proc_ns(new); + return list = new; + } + +@@ -624,6 +755,20 @@ dump_tree(current, 0, 1, 1, 1, u + dump_by_user(walk->child, uid); + } + ++static void dump_by_namespace(struct ns_entry *root) ++{ ++ struct ns_entry *ptr = root; ++ CHILD *c; ++ char buff[14]; ++ ++ for ( ; ptr; ptr = ptr->next) { ++ snprintf(buff, sizeof(buff), "[%li]\n", ptr->number); ++ out_string(buff); ++ for (c = ptr->children; c; c = c->next) ++ dump_tree(c->child, 0, 1, 1, 1, 0, 0); ++ } ++} ++ + static void trim_tree_by_parent(PROC * current) + { + if (!current) +@@ -853,6 +998,8 @@ static void usage(void) + " -G, --vt100 use VT100 line drawing characters\n" + " -l, --long don't truncate long lines\n" + " -n, --numeric-sort sort output by PID\n" ++ " -N type,\n" ++ " --ns-sort=type sort by namespace type (ipc, mnt, net, pid, user, uts)\n" + " -p, --show-pids show PIDs; implies -c\n" + " -s, --show-parents show parents of the selected process\n" + " -u, --uid-changes show uid transitions\n" +@@ -886,11 +1033,13 @@ int main(int argc, char **argv) + { + PROC *current; + struct winsize winsz; ++ struct ns_entry *nsroot = NULL; + const struct passwd *pw; + pid_t pid, highlight; + char termcap_area[1024]; + char *termname, *endptr; + int c, pid_set; ++ enum ns_type nsid = -1; + + struct option options[] = { + {"arguments", 0, NULL, 'a'}, +@@ -901,6 +1050,7 @@ {"highlight-all", 0, NULL, 'h'}, + {"highlight-pid", 1, NULL, 'H'}, + {"long", 0, NULL, 'l'}, + {"numeric-sort", 0, NULL, 'n'}, ++ {"ns-sort", 1, NULL, 'N' }, + {"show-pids", 0, NULL, 'p'}, + {"show-pgids", 0, NULL, 'g'}, + {"show-parents", 0, NULL, 's'}, +@@ -956,11 +1106,11 @@ /* problems with VT100 on some t + + #ifdef WITH_SELINUX + while ((c = +- getopt_long(argc, argv, "aAcGhH:npglsuUVZ", options, ++ getopt_long(argc, argv, "aAcGhH:nN:pglsuUVZ", options, + NULL)) != -1) + #else /*WITH_SELINUX */ + while ((c = +- getopt_long(argc, argv, "aAcGhH:npglsuUV", options, NULL)) != -1) ++ getopt_long(argc, argv, "aAcGhH:nN:pglsuUV", options, NULL)) != -1) + #endif /*WITH_SELINUX */ + switch (c) { + case 'a': +@@ -1002,6 +1152,17 @@ trunc = 0; + case 'n': + by_pid = 1; + break; ++ case 'N': ++ nsid = get_ns_id(optarg); ++ if (nsid == -1) ++ usage(); ++ if (verify_ns(nsid)) { ++ fprintf(stderr, ++ _("procfs file for %s namespace not available\n"), ++ optarg); ++ return 1; ++ } ++ break; + case 'p': + pids = 1; + compact = 0; +@@ -1059,7 +1220,10 @@ if (endptr[0] != '\0') + pid = ROOT_PID; + } + +- if (!pw) ++ if (nsid != -1) { ++ sort_by_namespace(NULL, nsid, &nsroot); ++ dump_by_namespace(nsroot); ++ } else if (!pw) + dump_tree(find_proc(pid), 0, 1, 1, 1, 0, 0); + else { + dump_by_user(find_proc(ROOT_PID), pw->pw_uid);