commit de7b3b9222ab4e2f75db88f0f75b555ab306140b Author: Aristeu Rozanski 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 --- 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 +#include +#include +#include +#include +#include +#include + +#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 match by real IDs\n" " -x, --exact match exactly with the command name\n" " -F, --pidfile 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 match the processes that belong to the same\n" + " namespace as \n" + " --nslist 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;