Blob Blame History Raw
commit de7b3b9222ab4e2f75db88f0f75b555ab306140b
Author: Aristeu Rozanski <arozansk@redhat.com>
Date:   Fri Apr 12 14:40:27 2013 -0400

    pgrep: introduce support for namespaces
    
    A PID should be specified with --ns:
    	$ pgrep --ns 12345
    which will only match the processes which belong to to the same 6
    namespaces. It is also possible to specify which namespaces to test:
    	$ pgrep --ns 12345 --nslist mnt,net,ipc
    which will match processes that belong to the same mount, network and
    IPC namespaces as PID 12345.
    
    Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>

---
 Makefile.am       |    4 +--
 include/nsutils.h |    7 +++++
 lib/nsutils.c     |   32 +++++++++++++++++++++++++
 pgrep.1           |    9 +++++++
 pgrep.c           |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 117 insertions(+), 4 deletions(-)

--- procps-ng-3.3.8.orig/Makefile.am	2013-05-25 17:39:39.000000000 -0400
+++ procps-ng-3.3.8/Makefile.am	2013-09-17 16:57:03.515128029 -0400
@@ -89,8 +89,8 @@ else
 endif
 
 free_SOURCES = free.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
-pgrep_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c
-pkill_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c
+pgrep_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c $(top_srcdir)/lib/nsutils.c
+pkill_SOURCES = pgrep.c $(top_srcdir)/lib/fileutils.c $(top_srcdir)/lib/nsutils.c
 pmap_SOURCES = pmap.c $(top_srcdir)/lib/fileutils.c
 pwdx_SOURCES = pwdx.c $(top_srcdir)/lib/fileutils.c
 sysctl_SOURCES = sysctl.c $(top_srcdir)/lib/fileutils.c
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ procps-ng-3.3.8/include/nsutils.h	2013-09-17 16:57:03.515128029 -0400
@@ -0,0 +1,7 @@
+#ifndef PROCPS_NG_NSUTILS
+#define PROCPS_NG_NSUTILS
+
+#include "proc/readproc.h"
+int ns_read(pid_t pid, proc_t *ns_task);
+
+#endif
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ procps-ng-3.3.8/lib/nsutils.c	2013-09-17 16:57:03.515128029 -0400
@@ -0,0 +1,32 @@
+#include <errno.h>
+#include <error.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "proc/readproc.h"
+#include "nsutils.h"
+
+/* we need to fill in only namespace information */
+int ns_read(pid_t pid, proc_t *ns_task)
+{
+	struct stat st;
+	char buff[50];
+	int i, rc = 0;
+
+	for (i = 0; i < NUM_NS; i++) {
+		snprintf(buff, sizeof(buff), "/proc/%i/ns/%s", pid,
+			get_ns_name(i));
+		if (stat(buff, &st)) {
+			if (errno != ENOENT)
+				rc = errno;
+			ns_task->ns[i] = 0;
+			continue;
+		}
+		ns_task->ns[i] = st.st_ino;
+	}
+	return rc;
+}
+
--- procps-ng-3.3.8.orig/pgrep.1	2013-05-25 17:39:40.000000000 -0400
+++ procps-ng-3.3.8/pgrep.1	2013-09-17 16:57:03.516128042 -0400
@@ -146,6 +146,15 @@ than
 \fB\-L\fR, \fB\-\-logpidfile\fR
 Fail if pidfile (see -F) not locked.
 .TP
+\fB\-\-ns \fIpid\fP
+Match processes that belong to the same namespaces. Required to run as
+root to match processes from other users. See \-\-nslist for how to limit
+which namespaces to match.
+.TP
+\fB\-\-nslist \fIname\fP,...
+Match only the provided namespaces. Available namespaces:
+ipc, mnt, net, pid, user,uts.
+.TP
 \fB\-V\fR, \fB\-\-version\fR
 Display version information and exit.
 .TP
--- procps-ng-3.3.8.orig/pgrep.c	2013-05-25 17:39:40.000000000 -0400
+++ procps-ng-3.3.8/pgrep.c	2013-09-17 16:58:18.439105071 -0400
@@ -46,6 +46,7 @@ #define CMDSTRSIZE 4096
 
 #include "c.h"
 #include "fileutils.h"
+#include "nsutils.h"
 #include "nls.h"
 #include "xalloc.h"
 #include "proc/readproc.h"
@@ -76,6 +77,7 @@ static int opt_lock = 0;
 static int opt_case = 0;
 static int opt_echo = 0;
 static int opt_threads = 0;
+static pid_t opt_ns_pid = 0;
 
 static const char *opt_delim = "\n";
 static struct el *opt_pgrp = NULL;
@@ -86,9 +88,13 @@ static struct el *opt_sid = NULL;
 static struct el *opt_term = NULL;
 static struct el *opt_euid = NULL;
 static struct el *opt_ruid = NULL;
+static struct el *opt_nslist = NULL;
 static char *opt_pattern = NULL;
 static char *opt_pidfile = NULL;
 
+/* by default, all namespaces will be checked */
+static int ns_flags = 0x3f;
+
 static int __attribute__ ((__noreturn__)) usage(int opt)
 {
 	int err = (opt == '?');
@@ -121,7 +127,12 @@ 	if (i_am_pkill == 0) {
 		" -U, --uid <id,...>        match by real IDs\n"
 		" -x, --exact               match exactly with the command name\n"
 		" -F, --pidfile <file>      read PIDs from file\n"
-		" -L, --logpidfile          fail if PID file is not locked\n"), fp);
+		" -L, --logpidfile          fail if PID file is not locked\n"
+		" --ns <pid>                match the processes that belong to the same\n"
+		"                           namespace as <pid>\n"
+		" --nslist <ns,...>         list which namespaces will be considered for\n"
+		"                           the --ns option.\n"
+		"                           Available namespaces: ipc, mnt, net, pid, user, uts\n"), fp);
 	fputs(USAGE_SEPARATOR, fp);
 	fputs(USAGE_HELP, fp);
 	fputs(USAGE_VERSION, fp);
@@ -320,6 +331,20 @@ static int conv_str (const char *restric
 }
 
 
+static int conv_ns (const char *restrict name, struct el *restrict e)
+{
+	int rc = conv_str(name, e);
+	int id;
+
+	ns_flags = 0;
+	id = get_ns_id(name);
+	if (id == -1)
+		return 0;
+	ns_flags |= (1 << id);
+
+	return rc;
+}
+
 static int match_numlist (long value, const struct el *restrict list)
 {
 	int found = 0;
@@ -350,6 +375,21 @@ 		for (i = list[0].num; i > 0; i--) {
 	return found;
 }
 
+static int match_ns (const proc_t *task, const proc_t *ns_task)
+{
+	int found = 1;
+	int i;
+
+	for (i = 0; i < NUM_NS; i++) {
+		if (ns_flags & (1 << i)) {
+			if (task->ns[i] != ns_task->ns[i])
+				found = 0;
+		}
+	}
+
+	return found;
+}
+
 static void output_numlist (const struct el *restrict list, int num)
 {
 	int i;
@@ -386,6 +426,8 @@ 	int flags = 0;
 		flags |= PROC_FILLSTAT;
 	if (!(flags & PROC_FILLSTAT))
 		flags |= PROC_FILLSTATUS;  /* FIXME: need one, and PROC_FILLANY broken */
+	if (opt_ns_pid)
+		flags |= PROC_FILLNS;
 	if (opt_euid && !opt_negate) {
 		int num = opt_euid[0].num;
 		int i = num;
@@ -442,6 +484,7 @@ 	int size = 0;
 	char cmdline[CMDSTRSIZE];
 	char cmdsearch[CMDSTRSIZE];
 	char cmdoutput[CMDSTRSIZE];
+	proc_t ns_task;
 
 	ptp = do_openproc();
 	preg = do_regcomp();
@@ -451,6 +494,11 @@ 	else saved_start_time = ~0ULL;
 
 	if (opt_newest) saved_pid = 0;
 	if (opt_oldest) saved_pid = INT_MAX;
+	if (opt_ns_pid && ns_read(opt_ns_pid, &ns_task)) {
+		fputs(_("Error reading reference namespace information\n"),
+		      stderr);
+		exit (EXIT_FATAL);
+	}
 
 	memset(&task, 0, sizeof (task));
 	while(readproc(ptp, &task)) {
@@ -476,6 +524,8 @@ 			match = 0;
 			match = 0;
 		else if (opt_sid && ! match_numlist (task.session, opt_sid))
 			match = 0;
+		else if (opt_ns_pid && ! match_ns (&task, &ns_task))
+			match = 0;
 		else if (opt_term) {
 			if (task.tty == 0) {
 				match = 0;
@@ -622,7 +672,9 @@ static void parse_opts (int argc, char *
 	int criteria_count = 0;
 
 	enum {
-		SIGNAL_OPTION = CHAR_MAX + 1
+		SIGNAL_OPTION = CHAR_MAX + 1,
+		NS_OPTION,
+		NSLIST_OPTION,
 	};
 	static const struct option longopts[] = {
 		{"signal", required_argument, NULL, SIGNAL_OPTION},
@@ -646,6 +698,8 @@ 	int criteria_count = 0;
 		{"pidfile", required_argument, NULL, 'F'},
 		{"logpidfile", no_argument, NULL, 'L'},
 		{"echo", no_argument, NULL, 'e'},
+		{"ns", required_argument, NULL, NS_OPTION},
+		{"nslist", required_argument, NULL, NSLIST_OPTION},
 		{"help", no_argument, NULL, 'h'},
 		{"version", no_argument, NULL, 'V'},
 		{NULL, 0, NULL, 0}
@@ -792,6 +846,17 @@ 		case 'l':   /* Solaris: long output fo
 			break;
 /*		case 'z':   / * Solaris: match by zone ID * /
  *			break; */
+		case NS_OPTION:
+			opt_ns_pid = atoi(optarg);
+			if (opt_ns_pid == 0)
+				usage (opt);
+			++criteria_count;
+			break;
+		case NSLIST_OPTION:
+			opt_nslist = split_list (optarg, conv_ns);
+			if (opt_nslist == NULL)
+				usage (opt);
+			break;
 		case 'h':
 			usage (opt);
 			break;