diff --git a/Makefile.am b/Makefile.am index 05128a46..3d66d60f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 9748a1de..8ef76835 100644 --- 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 03df229c..d3fc978b 100644 --- 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 expression is a terminal\n" " -u, --user expression is a username\n"), out); fputs(USAGE_SEPARATOR, out); + fputs(_("Alternatively, expression can be:\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"), 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)