2006ba
commit 91d225f3b8fcfa514f1ef20239af7b0ada64c01c
2006ba
Author: Aristeu Rozanski <arozansk@redhat.com>
2006ba
Date:   Tue Apr 16 12:07:10 2013 -0400
2006ba
2006ba
    skill: support namespaces
2006ba
    
2006ba
    In the same fashion of pgrep, introduce two new options:
2006ba
    	--ns <pid>
2006ba
    	- nslist <ns,...>
2006ba
    which allows processes to be filtered by namespace.
2006ba
    
2006ba
    Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
2006ba
2006ba
diff --git a/Makefile.am b/Makefile.am
2006ba
index 05128a4..3d66d60 100644
2006ba
--- a/Makefile.am
2006ba
+++ b/Makefile.am
2006ba
@@ -55,7 +55,7 @@ EXTRA_DIST = \
2006ba
 if BUILD_KILL
2006ba
 bin_PROGRAMS = kill
2006ba
 dist_man_MANS += kill.1
2006ba
-kill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
2006ba
+kill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c $(top_srcdir)/lib/nsutils.c
2006ba
 else
2006ba
   EXTRA_DIST += kill.1
2006ba
 endif
2006ba
@@ -77,8 +77,8 @@ if BUILD_SKILL
2006ba
 usrbin_exec_PROGRAMS += \
2006ba
 	skill \
2006ba
 	snice
2006ba
-skill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
2006ba
-snice_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c
2006ba
+skill_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c $(top_srcdir)/lib/nsutils.c
2006ba
+snice_SOURCES = skill.c $(top_srcdir)/lib/strutils.c $(top_srcdir)/lib/fileutils.c $(top_srcdir)/lib/nsutils.c
2006ba
 dist_man_MANS += \
2006ba
 	skill.1 \
2006ba
 	snice.1
2006ba
diff --git a/skill.1 b/skill.1
2006ba
index 9748a1d..8ef7683 100644
2006ba
--- a/skill.1
2006ba
+++ b/skill.1
2006ba
@@ -77,6 +77,13 @@ The next expression is a process ID number.
2006ba
 .TP
2006ba
 \fB\-c\fR, \fB\-\-command\fR \fIcommand\fR
2006ba
 The next expression is a command name.
2006ba
+.TP
2006ba
+\fB\-\-ns \fIpid\fR
2006ba
+Match the processes that belong to the same namespace as pid.
2006ba
+.TP
2006ba
+\fB\-\-nslist \fIns,...\fR
2006ba
+list which namespaces will be considered for the --ns option.
2006ba
+Available namespaces: ipc, mnt, net, pid, user, uts.
2006ba
 .PD
2006ba
 .SH SIGNALS
2006ba
 The behavior of signals is explained in
2006ba
diff --git a/skill.c b/skill.c
2006ba
index 03df229..d3fc978 100644
2006ba
--- a/skill.c
2006ba
+++ b/skill.c
2006ba
@@ -36,6 +36,7 @@
2006ba
 
2006ba
 #include "c.h"
2006ba
 #include "fileutils.h"
2006ba
+#include "nsutils.h"
2006ba
 #include "strutils.h"
2006ba
 #include "nls.h"
2006ba
 #include "xalloc.h"
2006ba
@@ -43,6 +44,7 @@
2006ba
 #include "proc/sig.h"
2006ba
 #include "proc/devname.h"
2006ba
 #include "proc/procps.h"	/* char *user_from_uid(uid_t uid) */
2006ba
+#include "proc/readproc.h"
2006ba
 #include "proc/version.h"	/* procps_version */
2006ba
 #include "rpmatch.h"
2006ba
 
2006ba
@@ -56,11 +58,14 @@ struct run_time_conf_t {
2006ba
 	int noaction;
2006ba
 	int debugging;
2006ba
 };
2006ba
-static int tty_count, uid_count, cmd_count, pid_count;
2006ba
+static int tty_count, uid_count, cmd_count, pid_count, namespace_count;
2006ba
 static int *ttys;
2006ba
 static uid_t *uids;
2006ba
 static const char **cmds;
2006ba
 static int *pids;
2006ba
+static char **namespaces;
2006ba
+static int ns_pid;
2006ba
+static proc_t ns_task;
2006ba
 
2006ba
 #define ENLIST(thing,addme) do{ \
2006ba
 if(!thing##s) thing##s = xmalloc(sizeof(*thing##s)*saved_argc); \
2006ba
@@ -85,6 +90,39 @@ static void display_kill_version(void)
2006ba
 	fprintf(stdout, PROCPS_NG_VERSION);
2006ba
 }
2006ba
 
2006ba
+static int ns_flags = 0x3f;
2006ba
+static int parse_namespaces(char *optarg)
2006ba
+{
2006ba
+	char *ptr = optarg, *tmp;
2006ba
+	int len, id;
2006ba
+
2006ba
+	ns_flags = 0;
2006ba
+	while (1) {
2006ba
+		if (strchr(ptr, ',') == NULL) {
2006ba
+			len = -1;
2006ba
+			tmp = strdup(ptr);
2006ba
+		} else {
2006ba
+			len = strchr(ptr, ',') - ptr;
2006ba
+			tmp = strndup(ptr, len);
2006ba
+		}
2006ba
+
2006ba
+		id = get_ns_id(tmp);
2006ba
+		if (id == -1) {
2006ba
+			fprintf(stderr, "%s is not a valid namespace\n", tmp);
2006ba
+			free(tmp);
2006ba
+			return 1;
2006ba
+		}
2006ba
+		ns_flags |= (1 << id);
2006ba
+		ENLIST(namespace, tmp);
2006ba
+
2006ba
+		if (len == -1)
2006ba
+			break;
2006ba
+
2006ba
+		ptr+= len + 1;
2006ba
+	}
2006ba
+	return 0;
2006ba
+}
2006ba
+
2006ba
 /* kill or nice a process */
2006ba
 static void hurt_proc(int tty, int uid, int pid, const char *restrict const cmd,
2006ba
 		      struct run_time_conf_t *run_time)
2006ba
@@ -131,6 +169,7 @@ static void check_proc(int pid, struct run_time_conf_t *run_time)
2006ba
 {
2006ba
 	char buf[128];
2006ba
 	struct stat statbuf;
2006ba
+	proc_t task;
2006ba
 	char *tmp;
2006ba
 	int tty;
2006ba
 	int fd;
2006ba
@@ -183,6 +222,16 @@ static void check_proc(int pid, struct run_time_conf_t *run_time)
2006ba
 		if (i == -1)
2006ba
 			goto closure;
2006ba
 	}
2006ba
+	if (ns_pid) {
2006ba
+		if (ns_read(pid, &task))
2006ba
+			goto closure;
2006ba
+		for (i = 0; i < NUM_NS; i++) {
2006ba
+			if (ns_flags & (1 << i)) {
2006ba
+				if (task.ns[i] != ns_task.ns[i])
2006ba
+					goto closure;
2006ba
+			}
2006ba
+		}
2006ba
+	}
2006ba
 	/* This is where we kill/nice something. */
2006ba
 	/* for debugging purposes?
2006ba
 	fprintf(stderr, "PID %d, UID %d, TTY %d,%d, COMM %s\n",
2006ba
@@ -317,6 +366,15 @@ static void __attribute__ ((__noreturn__)) skillsnice_usage(FILE * out)
2006ba
 		" -t, --tty <tty>          expression is a terminal\n"
2006ba
 		" -u, --user <username>    expression is a username\n"), out);
2006ba
 	fputs(USAGE_SEPARATOR, out);
2006ba
+	fputs(_("Alternatively, expression can be:\n"
2006ba
+		" --ns <pid>               match the processes that belong to the same\n"
2006ba
+		"                          namespace as <pid>\n"
2006ba
+		" --nslist <ns,...>        list which namespaces will be considered for\n"
2006ba
+		"                          the --ns option.\n"
2006ba
+		"                          Available namespaces: ipc, mnt, net, pid, user, uts\n"), out);
2006ba
+
2006ba
+	fputs(USAGE_SEPARATOR, out);
2006ba
+	fputs(USAGE_SEPARATOR, out);
2006ba
 	fputs(USAGE_HELP, out);
2006ba
 	fputs(USAGE_VERSION, out);
2006ba
 	if (program == PROG_SKILL) {
2006ba
@@ -488,6 +546,11 @@ static void skillsnice_parse(int argc,
2006ba
 	int prino = DEFAULT_NICE;
2006ba
 	int ch, i;
2006ba
 
2006ba
+	enum {
2006ba
+		NS_OPTION = CHAR_MAX + 1,
2006ba
+		NSLIST_OPTION,
2006ba
+	};
2006ba
+
2006ba
 	static const struct option longopts[] = {
2006ba
 		{"command", required_argument, NULL, 'c'},
2006ba
 		{"debug", no_argument, NULL, 'd'},
2006ba
@@ -499,6 +562,8 @@ static void skillsnice_parse(int argc,
2006ba
 		{"table", no_argument, NULL, 'L'},
2006ba
 		{"tty", required_argument, NULL, 't'},
2006ba
 		{"user", required_argument, NULL, 'u'},
2006ba
+		{"ns", required_argument, NULL, NS_OPTION},
2006ba
+		{"nslist", required_argument, NULL, NSLIST_OPTION},
2006ba
 		{"verbose", no_argument, NULL, 'v'},
2006ba
 		{"warnings", no_argument, NULL, 'w'},
2006ba
 		{"help", no_argument, NULL, 'h'},
2006ba
@@ -572,6 +637,25 @@ static void skillsnice_parse(int argc,
2006ba
 				}
2006ba
 			}
2006ba
 			break;
2006ba
+		case NS_OPTION:
2006ba
+			ns_pid = atoi(optarg);
2006ba
+			if (ns_pid == 0) {
2006ba
+				xwarnx(_("invalid pid number %i"), optarg);
2006ba
+				kill_usage(stderr);
2006ba
+			}
2006ba
+			if (ns_read(ns_pid, &ns_task)) {
2006ba
+				xwarnx(_("error reading reference namespace "
2006ba
+					 "information"));
2006ba
+				kill_usage(stderr);
2006ba
+			}	
2006ba
+
2006ba
+			break;
2006ba
+		case NSLIST_OPTION:
2006ba
+			if (parse_namespaces(optarg)) {
2006ba
+				xwarnx(_("invalid namespace list"));
2006ba
+				kill_usage(stderr);
2006ba
+			}
2006ba
+			break;
2006ba
 		case 'v':
2006ba
 			run_time->verbose = 1;
2006ba
 			break;
2006ba
@@ -605,7 +689,7 @@ static void skillsnice_parse(int argc,
2006ba
 	}
2006ba
 
2006ba
 	/* No more arguments to process. Must sanity check. */
2006ba
-	if (!tty_count && !uid_count && !cmd_count && !pid_count)
2006ba
+	if (!tty_count && !uid_count && !cmd_count && !pid_count && !ns_pid)
2006ba
 		xerrx(EXIT_FAILURE, _("no process selection criteria"));
2006ba
 	if ((run_time->fast | run_time->interactive | run_time->
2006ba
 	     verbose | run_time->warnings | run_time->noaction) & ~1)