]> granicus.if.org Git - procps-ng/commitdiff
skill: support namespaces
authorAristeu Rozanski <arozansk@redhat.com>
Tue, 16 Apr 2013 16:07:10 +0000 (12:07 -0400)
committerAristeu Rozanski <arozansk@redhat.com>
Thu, 18 Apr 2013 17:59:44 +0000 (13:59 -0400)
In the same fashion of pgrep, introduce two new options:
--ns <pid>
- nslist <ns,...>
which allows processes to be filtered by namespace.

Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
Makefile.am
skill.1
skill.c

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