[lxc-devel] [PATCH/RFC] Add lxc.stopsignal config option

Alexander Vladimirov alexander.idkfa.vladimirov at gmail.com
Tue Mar 12 09:14:11 UTC 2013


I remember discussion about implementing proper way to shutdown
guests using different signals, so here's a patch proposal.
It allows to use specific signal numbers to shutdown guests
gracefully, for example SIGRTMIN+4 starts poweroff.target in
systemd.

Signed-off-by: Alexander Vladimirov <alexander.idkfa.vladimirov at gmail.com>
---
 doc/lxc.conf.sgml.in | 23 ++++++++++++++
 src/lxc/conf.h       |  1 +
 src/lxc/confile.c    | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/stop.c       |  6 +++-
 4 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in
index ae91221..8ff1f20 100644
--- a/doc/lxc.conf.sgml.in
+++ b/doc/lxc.conf.sgml.in
@@ -130,6 +130,29 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     </refsect2>
 
     <refsect2>
+      <title>Stop signal</title>
+      <para>
+    Allows to specify signal name or number, sent by lxc-stop to
+    shutdown the container. Different init systems could use
+    different signals to perform clean shutdown sequence. Option
+    allows signal to be specified in kill(1) fashion, e.g.
+    SIGKILL, SIGRTMIN+14, SIGRTMAX-10 or plain number.
+      </para>
+      <variablelist>
+    <varlistentry>
+      <term>
+        <option>lxc.stopsignal</option>
+      </term>
+      <listitem>
+        <para>
+          specify the signal used to stop the container
+        </para>
+      </listitem>
+    </varlistentry>
+      </variablelist>
+    </refsect2>
+
+    <refsect2>
       <title>Network</title>
       <para>
 	The network section defines how the network is virtualized in
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index f20fb2f..61456ae 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -277,6 +277,7 @@ struct lxc_conf {
 #endif
 	int maincmd_fd;
 	int autodev;  // if 1, mount and fill a /dev at start
+	int stopsignal; // signal used to stop container
 	char *rcfile;	// Copy of the top level rcfile we read
 };
 
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index d350f01..8dbe83d 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -27,6 +27,8 @@
 #include <unistd.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -87,6 +89,7 @@ static int config_seccomp(const char *, const char *, struct lxc_conf *);
 static int config_includefile(const char *, const char *, struct lxc_conf *);
 static int config_network_nic(const char *, const char *, struct lxc_conf *);
 static int config_autodev(const char *, const char *, struct lxc_conf *);
+static int config_stopsignal(const char *, const char *, struct lxc_conf *);
 
 static struct lxc_config_t config[] = {
 
@@ -134,6 +137,34 @@ static struct lxc_config_t config[] = {
 	{ "lxc.seccomp",              config_seccomp              },
 	{ "lxc.include",              config_includefile          },
 	{ "lxc.autodev",              config_autodev              },
+	{ "lxc.stopsignal",           config_stopsignal           },
+};
+
+struct signame {
+	int num;
+	char *name;
+};
+
+struct signame signames[] = {
+	{ SIGHUP,    "HUP" },
+	{ SIGINT,    "INT" },
+	{ SIGQUIT,   "QUIT" },
+	{ SIGILL,    "ILL" },
+	{ SIGABRT,   "ABRT" },
+	{ SIGFPE,    "FPE" },
+	{ SIGKILL,   "KILL" },
+	{ SIGSEGV,   "SEGV" },
+	{ SIGPIPE,   "PIPE" },
+	{ SIGALRM,   "ALRM" },
+	{ SIGTERM,   "TERM" },
+	{ SIGUSR1,   "USR1" },
+	{ SIGUSR2,   "USR2" },
+	{ SIGCHLD,   "CHLD" },
+	{ SIGCONT,   "CONT" },
+	{ SIGSTOP,   "STOP" },
+	{ SIGTSTP,   "TSTP" },
+	{ SIGTTIN,   "TTIN" },
+	{ SIGTTOU,   "TTOU" },
 };
 
 static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
@@ -959,6 +990,65 @@ static int config_autodev(const char *key, const char *value,
 	return 0;
 }
 
+static int sig_num(const char *sig)
+{
+	int n;
+	char *endp = NULL;
+
+	errno = 0;
+	n = strtol(sig, &endp, 10);
+	if (sig == endp || n < 0 || errno != 0)
+		return -1;
+	return n;
+}
+
+static int rt_sig_num(const char *signame)
+{
+	int sig_n = 0;
+	int rtmax = 0;
+
+	if (strncasecmp(signame, "max-", 4) == 0) {
+		rtmax = 1;
+	}
+	signame += 4;
+	if (!isdigit(*signame))
+		return -1;
+	sig_n = sig_num(signame);
+	sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
+	if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
+		return -1;
+	return sig_n;
+}
+
+static int sig_parse(const char *signame) {
+	int n;
+
+	if (isdigit(*signame)) {
+		return sig_num(signame);
+	} else if (strncasecmp(signame, "sig", 3) == 0) {
+		signame += 3;
+		if (strncasecmp(signame, "rt", 2) == 0)
+			return rt_sig_num(signame + 2);
+		for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
+			if (strcasecmp (signames[n].name, signame) == 0)
+				return signames[n].num;
+		}
+	}
+	return -1;
+}
+
+static int config_stopsignal(const char *key, const char *value,
+			  struct lxc_conf *lxc_conf)
+{
+	int sig_n = sig_parse(value);
+
+	if (sig_n < 0)
+		return -1;
+	lxc_conf->stopsignal = sig_n;
+
+	return 0;
+}
+
 static int config_cgroup(const char *key, const char *value,
 			 struct lxc_conf *lxc_conf)
 {
diff --git a/src/lxc/stop.c b/src/lxc/stop.c
index 851a4bf..7fea6b6 100644
--- a/src/lxc/stop.c
+++ b/src/lxc/stop.c
@@ -34,6 +34,7 @@
 
 #include <lxc/log.h>
 #include <lxc/start.h>
+#include <lxc/conf.h>
 
 #include "lxc.h"
 #include "commands.h"
@@ -82,9 +83,12 @@ extern int lxc_stop_callback(int fd, struct lxc_request *request,
 {
 	struct lxc_answer answer;
 	int ret;
+	int stopsignal = SIGKILL;
 
+	if (handler->conf->stopsignal)
+		stopsignal = handler->conf->stopsignal;
 	memset(&answer, 0, sizeof(answer));
-	answer.ret = kill(handler->pid, SIGKILL);
+	answer.ret = kill(handler->pid, stopsignal);
 	if (!answer.ret) {
 		ret = lxc_unfreeze_bypath(handler->cgroup);
 		if (!ret)
-- 
1.8.1.5





More information about the lxc-devel mailing list