[lxc-devel] [lxc/master] console: exit mainloop on SIGTERM

brauner on Github lxc-bot at linuxcontainers.org
Sun Nov 12 17:45:31 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 469 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171112/efc88519/attachment.bin>
-------------- next part --------------
From 21def5ee654ab10edc52d2054ade8601662de96d Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 12 Nov 2017 15:25:19 +0100
Subject: [PATCH 1/3] console: prepare for generic signal handler

Non-functional changes to enable handling more signals.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/console.c | 45 +++++++++++++++++++++++----------------------
 src/lxc/console.h | 48 +++++++++++++++++++++++++++---------------------
 2 files changed, 50 insertions(+), 43 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index 4af0481ca..a97501342 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -93,15 +93,15 @@ void lxc_console_sigwinch(int sig)
 	}
 }
 
-int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
-		struct lxc_epoll_descr *descr)
+int lxc_console_cb_signal_fd(int fd, uint32_t events, void *cbdata,
+			       struct lxc_epoll_descr *descr)
 {
 	struct signalfd_siginfo siginfo;
 	struct lxc_tty_state *ts = cbdata;
 
 	ssize_t ret = read(fd, &siginfo, sizeof(siginfo));
 	if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
-		ERROR("failed to read signal info");
+		ERROR("Failed to read signal info");
 		return -1;
 	}
 
@@ -109,8 +109,9 @@ int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
 	return 0;
 }
 
-struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
+struct lxc_tty_state *lxc_console_signal_init(int srcfd, int dstfd)
 {
+	bool istty;
 	sigset_t mask;
 	struct lxc_tty_state *ts;
 
@@ -123,7 +124,8 @@ struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 	ts->masterfd = dstfd;
 	ts->sigfd = -1;
 
-	if (!isatty(srcfd)) {
+	istty = isatty(srcfd) == 1;
+	if (!istty) {
 		INFO("fd %d does not refer to a tty device", srcfd);
 		return ts;
 	}
@@ -135,7 +137,7 @@ struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 	sigemptyset(&mask);
 	sigaddset(&mask, SIGWINCH);
 	if (sigprocmask(SIG_BLOCK, &mask, &ts->oldmask)) {
-		SYSERROR("failed to block SIGWINCH");
+		SYSERROR("Failed to block SIGWINCH signal");
 		ts->sigfd = -1;
 		lxc_list_del(&ts->node);
 		return ts;
@@ -143,18 +145,18 @@ struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
 
 	ts->sigfd = signalfd(-1, &mask, 0);
 	if (ts->sigfd < 0) {
-		SYSERROR("failed to create signal fd");
+		SYSERROR("Failed to create signal fd");
 		sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
 		ts->sigfd = -1;
 		lxc_list_del(&ts->node);
 		return ts;
 	}
 
-	DEBUG("process %d created signal fd %d to handle SIGWINCH events", getpid(), ts->sigfd);
+	DEBUG("Process %d created signal fd %d", getpid(), ts->sigfd);
 	return ts;
 }
 
-void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
+void lxc_console_signal_fini(struct lxc_tty_state *ts)
 {
 	if (ts->sigfd >= 0) {
 		close(ts->sigfd);
@@ -178,7 +180,7 @@ static int lxc_console_cb_con(int fd, uint32_t events, void *data,
 		lxc_mainloop_del_handler(descr, fd);
 		if (fd == console->peer) {
 			if (console->tty_state) {
-				lxc_console_sigwinch_fini(console->tty_state);
+				lxc_console_signal_fini(console->tty_state);
 				console->tty_state = NULL;
 			}
 			console->peer = -1;
@@ -225,16 +227,15 @@ static void lxc_console_mainloop_add_peer(struct lxc_console *console)
 	if (console->peer >= 0) {
 		if (lxc_mainloop_add_handler(console->descr, console->peer,
 					     lxc_console_cb_con, console))
-			WARN("console peer not added to mainloop");
+			WARN("Failed to add console peer handler to mainloop");
 	}
 
 	if (console->tty_state && console->tty_state->sigfd != -1) {
 		if (lxc_mainloop_add_handler(console->descr,
 					     console->tty_state->sigfd,
-					     lxc_console_cb_sigwinch_fd,
+					     lxc_console_cb_signal_fd,
 					     console->tty_state)) {
-			WARN("failed to add to mainloop SIGWINCH handler for '%d'",
-			     console->tty_state->sigfd);
+			WARN("Failed to add signal handler to mainloop");
 		}
 	}
 }
@@ -321,7 +322,7 @@ int lxc_setup_tios(int fd, struct termios *oldtios)
 static void lxc_console_peer_proxy_free(struct lxc_console *console)
 {
 	if (console->tty_state) {
-		lxc_console_sigwinch_fini(console->tty_state);
+		lxc_console_signal_fini(console->tty_state);
 		console->tty_state = NULL;
 	}
 	close(console->peerpty.master);
@@ -367,7 +368,7 @@ static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
 	if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
 		goto err1;
 
-	ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
+	ts = lxc_console_signal_init(console->peerpty.master, console->master);
 	if (!ts)
 		goto err1;
 
@@ -479,10 +480,10 @@ static int lxc_console_peer_default(struct lxc_console *console)
 		goto on_error1;
 	}
 
-	ts = lxc_console_sigwinch_init(console->peer, console->master);
+	ts = lxc_console_signal_init(console->peer, console->master);
 	console->tty_state = ts;
 	if (!ts) {
-		WARN("unable to install SIGWINCH handler");
+		WARN("Failed to install signal handler");
 		goto on_error1;
 	}
 
@@ -785,7 +786,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
 	if (ret < 0)
 		TRACE("Process is already group leader");
 
-	ts = lxc_console_sigwinch_init(stdinfd, masterfd);
+	ts = lxc_console_signal_init(stdinfd, masterfd);
 	if (!ts) {
 		ret = -1;
 		goto close_fds;
@@ -811,9 +812,9 @@ int lxc_console(struct lxc_container *c, int ttynum,
 
 	if (ts->sigfd != -1) {
 		ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
-					       lxc_console_cb_sigwinch_fd, ts);
+					       lxc_console_cb_signal_fd, ts);
 		if (ret < 0) {
-			ERROR("Failed to add SIGWINCH handler");
+			ERROR("Failed to add signal handler to mainloop");
 			goto close_mainloop;
 		}
 	}
@@ -867,7 +868,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
 	lxc_mainloop_close(&descr);
 
 sigwinch_fini:
-	lxc_console_sigwinch_fini(ts);
+	lxc_console_signal_fini(ts);
 
 close_fds:
 	close(masterfd);
diff --git a/src/lxc/console.h b/src/lxc/console.h
index 50dfd2e1c..389914ab5 100644
--- a/src/lxc/console.h
+++ b/src/lxc/console.h
@@ -24,6 +24,9 @@
 #ifndef __LXC_CONSOLE_H
 #define __LXC_CONSOLE_H
 
+#include <signal.h>
+#include <stdio.h>
+
 #include "conf.h"
 #include "list.h"
 
@@ -38,18 +41,21 @@ struct lxc_tty_state
 	/* Escape sequence to use for exiting the pty. A single char can be
 	 * specified. The pty can then exited by doing: Ctrl + specified_char + q.
 	 * This field is checked by lxc_console_cb_tty_stdin(). Set to -1 to
-	 * disable exiting the pty via a escape sequence. */
+	 * disable exiting the pty via a escape sequence.
+	 */
 	int escape;
 	/* Used internally by lxc_console_cb_tty_stdin() to check whether an
-	 * escape sequence has been received. */
+	 * escape sequence has been received.
+	 */
 	int saw_escape;
 	/* Name of the container to forward the SIGWINCH event to. */
 	const char *winch_proxy;
 	/* Path of the container to forward the SIGWINCH event to. */
 	const char *winch_proxy_lxcpath;
-	/* File descriptor that accepts SIGWINCH signals. If set to -1 no
-	 * SIGWINCH handler could be installed. This also means that
-	 * the sigset_t oldmask member is meaningless. */
+	/* File descriptor that accepts signals. If set to -1 no signal handler
+	 * could be installed. This also means that the sigset_t oldmask member
+	 * is meaningless.
+	 */
 	int sigfd;
 	sigset_t oldmask;
 };
@@ -172,48 +178,48 @@ extern int lxc_setup_tios(int fd, struct termios *oldtios);
 extern void lxc_console_winsz(int srcfd, int dstfd);
 
 /*
- * lxc_console_sigwinch_init: install SIGWINCH handler
+ * lxc_console_signal_init: install signal handler
  *
  * @srcfd  : src for winsz in SIGWINCH handler
  * @dstfd  : dst for winsz in SIGWINCH handler
  *
  * Returns lxc_tty_state structure on success or NULL on failure. The sigfd
  * member of the returned lxc_tty_state can be select()/poll()ed/epoll()ed
- * on (ie added to a mainloop) for SIGWINCH.
+ * on (ie added to a mainloop) for signals.
  *
  * Must be called with process_lock held to protect the lxc_ttys list, or
  * from a non-threaded context.
  *
- * Note that SIGWINCH isn't installed as a classic asychronous handler,
- * rather signalfd(2) is used so that we can handle the signal when we're
- * ready for it. This avoids deadlocks since a signal handler
- * (ie lxc_console_sigwinch()) would need to take the thread mutex to
- * prevent lxc_ttys list corruption, but using the fd we can provide the
- * tty_state needed to the callback (lxc_console_cb_sigwinch_fd()).
+ * Note that the signal handler isn't installed as a classic asychronous
+ * handler, rather signalfd(2) is used so that we can handle the signal when
+ * we're ready for it. This avoids deadlocks since a signal handler (ie
+ * lxc_console_sigwinch()) would need to take the thread mutex to prevent
+ * lxc_ttys list corruption, but using the fd we can provide the tty_state
+ * needed to the callback (lxc_console_cb_signal_fd()).
  *
  * This function allocates memory. It is up to the caller to free it.
  */
-extern struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd);
+extern struct lxc_tty_state *lxc_console_signal_init(int srcfd, int dstfd);
 
 /*
- * Handler for SIGWINCH events. To be registered via the corresponding functions
+ * Handler for signal events. To be registered via the corresponding functions
  * declared and defined in mainloop.{c,h} or lxc_console_mainloop_add().
  */
-extern int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
-		struct lxc_epoll_descr *descr);
+extern int lxc_console_cb_signal_fd(int fd, uint32_t events, void *cbdata,
+				    struct lxc_epoll_descr *descr);
 
 /*
- * lxc_console_sigwinch_fini: uninstall SIGWINCH handler
+ * lxc_console_signal_fini: uninstall signal handler
  *
- * @ts  : the lxc_tty_state returned by lxc_console_sigwinch_init
+ * @ts  : the lxc_tty_state returned by lxc_console_signal_init
  *
  * Restore the saved signal handler that was in effect at the time
- * lxc_console_sigwinch_init() was called.
+ * lxc_console_signal_init() was called.
  *
  * Must be called with process_lock held to protect the lxc_ttys list, or
  * from a non-threaded context.
  */
-extern void lxc_console_sigwinch_fini(struct lxc_tty_state *ts);
+extern void lxc_console_signal_fini(struct lxc_tty_state *ts);
 
 extern int lxc_console_write_ringbuffer(struct lxc_console *console);
 

From bee94b6ff0137734e43339431defdc5dded7faa0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 12 Nov 2017 15:26:15 +0100
Subject: [PATCH 2/3] tools: adapt lxc-attach to console changes

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/tools/lxc_attach.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 306bcaf01..47a4f0c27 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -371,7 +371,7 @@ static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *
 	lxc_mainloop_close(&descr);
 err2:
 	if (ts && ts->sigfd != -1)
-		lxc_console_sigwinch_fini(ts);
+		lxc_console_signal_fini(ts);
 err1:
 	lxc_console_delete(&conf->console);
 

From 0f05aea76579e6ddd351b4c76e2ff7a37aecfbb5 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 12 Nov 2017 17:51:11 +0100
Subject: [PATCH 3/3] console: exit mainloop on SIGTERM

This allows cleanly exiting a console session without control sequences.

Relates to https://github.com/lxc/lxd/pull/4001 .

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/console.c | 63 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 43 insertions(+), 20 deletions(-)

diff --git a/src/lxc/console.c b/src/lxc/console.c
index a97501342..6ed03351f 100644
--- a/src/lxc/console.c
+++ b/src/lxc/console.c
@@ -96,21 +96,30 @@ void lxc_console_sigwinch(int sig)
 int lxc_console_cb_signal_fd(int fd, uint32_t events, void *cbdata,
 			       struct lxc_epoll_descr *descr)
 {
+	ssize_t ret;
 	struct signalfd_siginfo siginfo;
 	struct lxc_tty_state *ts = cbdata;
 
-	ssize_t ret = read(fd, &siginfo, sizeof(siginfo));
+	ret = read(fd, &siginfo, sizeof(siginfo));
 	if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
 		ERROR("Failed to read signal info");
 		return -1;
 	}
 
-	lxc_console_winch(ts);
+	if (siginfo.ssi_signo == SIGTERM) {
+		DEBUG("Received SIGTERM. Detaching from the console");
+		return 1;
+	}
+
+	if (siginfo.ssi_signo == SIGWINCH)
+		lxc_console_winch(ts);
+
 	return 0;
 }
 
 struct lxc_tty_state *lxc_console_signal_init(int srcfd, int dstfd)
 {
+	int ret;
 	bool istty;
 	sigset_t mask;
 	struct lxc_tty_state *ts;
@@ -124,35 +133,45 @@ struct lxc_tty_state *lxc_console_signal_init(int srcfd, int dstfd)
 	ts->masterfd = dstfd;
 	ts->sigfd = -1;
 
+	sigemptyset(&mask);
+
 	istty = isatty(srcfd) == 1;
 	if (!istty) {
 		INFO("fd %d does not refer to a tty device", srcfd);
-		return ts;
+	} else {
+		/* Add tty to list to be scanned at SIGWINCH time. */
+		lxc_list_add_elem(&ts->node, ts);
+		lxc_list_add_tail(&lxc_ttys, &ts->node);
+		sigaddset(&mask, SIGWINCH);
 	}
 
-	/* add tty to list to be scanned at SIGWINCH time */
-	lxc_list_add_elem(&ts->node, ts);
-	lxc_list_add_tail(&lxc_ttys, &ts->node);
+	/* Exit the mainloop cleanly on SIGTERM. */
+	sigaddset(&mask, SIGTERM);
 
-	sigemptyset(&mask);
-	sigaddset(&mask, SIGWINCH);
-	if (sigprocmask(SIG_BLOCK, &mask, &ts->oldmask)) {
-		SYSERROR("Failed to block SIGWINCH signal");
-		ts->sigfd = -1;
-		lxc_list_del(&ts->node);
-		return ts;
+	ret = sigprocmask(SIG_BLOCK, &mask, &ts->oldmask);
+	if (ret < 0) {
+		WARN("Failed to block signals");
+		goto on_error;
 	}
 
 	ts->sigfd = signalfd(-1, &mask, 0);
 	if (ts->sigfd < 0) {
-		SYSERROR("Failed to create signal fd");
+		WARN("Failed to create signal fd");
 		sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
-		ts->sigfd = -1;
-		lxc_list_del(&ts->node);
-		return ts;
+		goto on_error;
 	}
 
-	DEBUG("Process %d created signal fd %d", getpid(), ts->sigfd);
+	DEBUG("Created signal fd %d", ts->sigfd);
+	return ts;
+
+on_error:
+	ERROR("Failed to create signal fd");
+	if (ts->sigfd >= 0) {
+		close(ts->sigfd);
+		ts->sigfd = -1;
+	}
+	if (istty)
+		lxc_list_del(&ts->node);
 	return ts;
 }
 
@@ -160,10 +179,14 @@ void lxc_console_signal_fini(struct lxc_tty_state *ts)
 {
 	if (ts->sigfd >= 0) {
 		close(ts->sigfd);
-		lxc_list_del(&ts->node);
-		sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
+
+		if (sigprocmask(SIG_SETMASK, &ts->oldmask, NULL) < 0)
+			WARN("%s - Failed to restore signal mask", strerror(errno));
 	}
 
+	if (isatty(ts->stdinfd))
+		lxc_list_del(&ts->node);
+
 	free(ts);
 }
 


More information about the lxc-devel mailing list