summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAristeu Rozanski <arozansk@redhat.com>2013-04-12 14:40:27 -0400
committerAristeu Rozanski <arozansk@redhat.com>2013-04-16 15:05:31 -0400
commitde7b3b9222ab4e2f75db88f0f75b555ab306140b (patch)
tree258e48ea77c7ad9ffa8b5a6ce48b7bd393419a87
parenta01ee3c0b32d4c39aa83066ed61103343469527e (diff)
downloadprocps-ng-de7b3b9222ab4e2f75db88f0f75b555ab306140b.tar.gz
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>
-rw-r--r--Makefile.am4
-rw-r--r--include/nsutils.h7
-rw-r--r--lib/nsutils.c32
-rw-r--r--pgrep.19
-rw-r--r--pgrep.c69
5 files changed, 117 insertions, 4 deletions
diff --git a/Makefile.am b/Makefile.am
index 9e900ac..05128a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/include/nsutils.h b/include/nsutils.h
new file mode 100644
index 0000000..3235851
--- /dev/null
+++ b/include/nsutils.h
@@ -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
diff --git a/lib/nsutils.c b/lib/nsutils.c
new file mode 100644
index 0000000..b97f446
--- /dev/null
+++ b/lib/nsutils.c
@@ -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;
+}
+
diff --git a/pgrep.1 b/pgrep.1
index a0e7376..c9860c7 100644
--- a/pgrep.1
+++ b/pgrep.1
@@ -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
diff --git a/pgrep.c b/pgrep.c
index 349221a..06fd8b8 100644
--- a/pgrep.c
+++ b/pgrep.c
@@ -46,6 +46,7 @@
#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 @@ static int __attribute__ ((__noreturn__)) usage(int opt)
" -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 *restrict name, struct el *restrict e)
}
+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 @@ static int match_strlist (const char *restrict value, const struct el *restrict
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 @@ static PROCTAB *do_openproc (void)
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 @@ static struct el * select_procs (int *num)
char cmdline[CMDSTRSIZE];
char cmdsearch[CMDSTRSIZE];
char cmdoutput[CMDSTRSIZE];
+ proc_t ns_task;
ptp = do_openproc();
preg = do_regcomp();
@@ -451,6 +494,11 @@ static struct el * select_procs (int *num)
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 @@ static struct el * select_procs (int *num)
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 **argv)
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 @@ static void parse_opts (int argc, char **argv)
{"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 @@ static void parse_opts (int argc, char **argv)
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;