From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 636F1139694 for ; Fri, 19 May 2017 23:30:04 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 910B7E0E72; Fri, 19 May 2017 23:30:03 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 55FCDE0E72 for ; Fri, 19 May 2017 23:30:03 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id CF57D34169C for ; Fri, 19 May 2017 23:30:01 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 1DAA27453 for ; Fri, 19 May 2017 23:30:00 +0000 (UTC) From: "William Hubbs" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "William Hubbs" Message-ID: <1495235619.49b8a573a195f4b2cee992cd10678694da0a6f4f.williamh@OpenRC> Subject: [gentoo-commits] proj/openrc:master commit in: src/rc/ X-VCS-Repository: proj/openrc X-VCS-Files: src/rc/.gitignore src/rc/Makefile src/rc/kill_all.c X-VCS-Directories: src/rc/ X-VCS-Committer: williamh X-VCS-Committer-Name: William Hubbs X-VCS-Revision: 49b8a573a195f4b2cee992cd10678694da0a6f4f X-VCS-Branch: master Date: Fri, 19 May 2017 23:30:00 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 0fcba550-0c6f-474d-89bd-f44ecdb8867f X-Archives-Hash: f9a9babb27aaee29e4a991661097238c commit: 49b8a573a195f4b2cee992cd10678694da0a6f4f Author: William Hubbs gmail com> AuthorDate: Fri May 19 18:37:30 2017 +0000 Commit: William Hubbs gentoo org> CommitDate: Fri May 19 23:13:39 2017 +0000 URL: https://gitweb.gentoo.org/proj/openrc.git/commit/?id=49b8a573 add kill_all helper This is similar to the sysvinit killall5 utility. It should only be used in service scripts, so it will not be installed in the path. This closes #129. src/rc/.gitignore | 1 + src/rc/Makefile | 6 +- src/rc/kill_all.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+), 1 deletion(-) diff --git a/src/rc/.gitignore b/src/rc/.gitignore index c3e7b3f6..91d57075 100644 --- a/src/rc/.gitignore +++ b/src/rc/.gitignore @@ -62,3 +62,4 @@ openrc openrc-init openrc-run openrc-shutdown +kill_all diff --git a/src/rc/Makefile b/src/rc/Makefile index 2bc03f76..5874ed17 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -14,7 +14,7 @@ SRCS+= rc-selinux.c endif ifeq (${OS},Linux) -SRCS+= openrc-init.c openrc-shutdown.c +SRCS+= kill_all.c openrc-init.c openrc-shutdown.c endif CLEANFILES= version.h rc-selinux.o @@ -44,6 +44,7 @@ RC_SBINPROGS= mark_service_starting mark_service_started \ rc-abort swclock ifeq (${OS},Linux) +RC_BINPROGS+= kill_all SBINPROGS+= openrc-init openrc-shutdown endif @@ -99,6 +100,9 @@ checkpath: rc-selinux.o endif ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} +kill_all: kill_all.o _usage.o + ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} + einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \ eindent eoutdent esyslog eval_ecolors ewaitfile \ veinfo vewarn vebegin veend vewend veindent veoutdent: do_e.o rc-misc.o diff --git a/src/rc/kill_all.c b/src/rc/kill_all.c new file mode 100644 index 00000000..a4b15c87 --- /dev/null +++ b/src/rc/kill_all.c @@ -0,0 +1,250 @@ +/* + * kill_all.c + * Sends a signal to all processes on the system. + */ + +/* + * Copyright (c) 2017 The OpenRC Authors. + * See the Authors file at the top-level directory of this distribution and + * https://github.com/OpenRC/openrc/blob/master/AUTHORS + * + * This file is part of OpenRC. It is subject to the license terms in + * the LICENSE file found in the top-level directory of this + * distribution and at https://github.com/OpenRC/openrc/blob/master/LICENSE + * This file may not be copied, modified, propagated, or distributed + * except according to the terms contained in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" +#include "_usage.h" + +const char *applet = NULL; +const char *extraopts = "[signal number]"; +const char *getoptstring = "do:" getoptstring_COMMON; +const struct option longopts[] = { + { "dry-run", 0, NULL, 'd' }, + { "omit", 1, NULL, 'o' }, + longopts_COMMON +}; +const char * const longopts_help[] = { + "print what would be done", + "omit this pid (can be repeated)", + longopts_help_COMMON +}; +const char *usagestring = NULL; + +static int mount_proc(void) +{ + pid_t pid; + pid_t rc; + int status; + + if (exists("/proc/version")) + return 0; + pid = fork(); + switch(pid) { + case -1: + syslog(LOG_ERR, "Unable to fork"); + return -1; + break; + case 0: + /* attempt to mount /proc */ + execl("mount", "mount", "-t", "proc", "proc", "/proc", NULL); + syslog(LOG_ERR, "Unable to execute mount"); + exit(1); + break; + default: + /* wait for child process */ + while ((rc = wait(&status)) != pid) + if (rc < 0 && errno == ECHILD) + break; + if (rc != pid || WEXITSTATUS(status) != 0) + syslog(LOG_ERR, "mount returned non-zero exit status"); + break; + } + if (! exists("/proc/version")) { + syslog(LOG_ERR, "Could not mount /proc"); + return -1; + } + return 0; +} + +static bool is_user_process(pid_t pid) +{ + char buf[PATH_MAX+1]; + FILE *fp; + char path[PATH_MAX+1]; + pid_t temp_pid; + bool user_process = true; + + while (pid >0 && user_process) { + if (pid == 2) { + user_process = false; + continue; + } + snprintf(path, sizeof(path), "/proc/%d/status", pid); + fp = fopen(path, "r"); + /* + * if we could not open the file, the process disappeared, which + * leaves us no way to determine for sure whether it was a user + * process or kernel thread, so we say it is a kernel thread to + * avoid accidentally killing it. + */ + if (!fp) { + user_process = false; + continue; + } + temp_pid = -1; + while (! feof(fp)) { + buf[0] = 0; + if (fgets(buf, sizeof(buf), fp)) + sscanf(buf, "PPid: %d", &temp_pid); + else + break; + } + fclose(fp); + if (temp_pid == -1) { + syslog(LOG_ERR, "Unable to read pid from /proc/%d/status", pid); + user_process = false; + continue; + } + pid = temp_pid; + } + return user_process; +} + +static int signal_processes(int sig, RC_STRINGLIST *omits, bool dryrun) +{ + sigset_t signals; + sigset_t oldsigs; + DIR *dir; + struct dirent *d; + char buf[PATH_MAX+1]; + pid_t pid; + int sendcount = 0; + + kill(-1, SIGSTOP); + sigfillset(&signals); + sigemptyset(&oldsigs); + sigprocmask(SIG_SETMASK, &signals, &oldsigs); + /* + * Open the /proc directory. + * CWD must be /proc to avoid problems if / is affected by the killing + * (i.e. depends on fuse). + */ + if (chdir("/proc") == -1) { + syslog(LOG_ERR, "chdir /proc failed"); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return -1; + } + dir = opendir("."); + if (!dir) { + syslog(LOG_ERR, "cannot opendir(/proc)"); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return -1; + } + + /* Walk through the directory. */ + while ((d = readdir(dir)) != NULL) { + /* Is this a process? */ + pid = (pid_t) atoi(d->d_name); + if (pid == 0) + continue; + + /* Is this a process we have been requested to omit? */ + sprintf(buf, "%d", pid); + if (rc_stringlist_find(omits, buf)) + continue; + + /* Is this process in our session? */ + if (getsid(getpid()) == getsid(pid)) + continue; + + /* Is this a kernel thread? */ + if (!is_user_process(pid)) + continue; + + if (dryrun) + einfo("Would send signal %d to process %d", sig, pid); + else if (kill(pid, sig) == 0) + sendcount++; + } + closedir(dir); + sigprocmask(SIG_SETMASK, &oldsigs, NULL); + kill(-1, SIGCONT); + return sendcount; +} + +int main(int argc, char **argv) +{ + char *arg = NULL; + int opt; + bool dryrun = false; + RC_STRINGLIST *omits = rc_stringlist_new(); + int sig = SIGKILL; + char *here; + char *token; + + /* Ensure that we are only quiet when explicitly told to be */ + unsetenv("EINFO_QUIET"); + + applet = basename_c(argv[0]); + rc_stringlist_addu(omits, "1"); + while ((opt = getopt_long(argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'd': + dryrun = true; + break; + case 'o': + here = optarg; + while ((token = strsep(&here, ",;:"))) { + if ((pid_t) atoi(token) > 0) + rc_stringlist_addu(omits, token); + else { + eerror("Invalid omit pid value %s", token); + usage(EXIT_FAILURE); + } + } + break; + case_RC_COMMON_GETOPT + } + } + + if (argc > optind) { + arg = argv[optind]; + sig = atoi(arg); + if (sig <= 0 || sig > 31) { + rc_stringlist_free(omits); + eerror("Invalid signal %s", arg); + usage(EXIT_FAILURE); + } + } + + openlog(applet, LOG_CONS|LOG_PID, LOG_DAEMON); + if (mount_proc() != 0) { + rc_stringlist_free(omits); + eerrorx("Unable to mount /proc file system"); + } + signal_processes(sig, omits, dryrun); + rc_stringlist_free(omits); + return 0; +}