console: prepare for generic signal handler

Non-functional changes to enable handling more signals. Signed-off-by: 's avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 8a01a32f
......@@ -57,25 +57,39 @@ static struct lxc_list lxc_ttys;
typedef void (*sighandler_t)(int);
__attribute__((constructor))
void lxc_console_init(void)
__attribute__((constructor)) void lxc_console_init(void)
{
lxc_list_init(&lxc_ttys);
}
void lxc_console_winsz(int srcfd, int dstfd)
{
int ret;
struct winsize wsz;
if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
DEBUG("set winsz dstfd:%d cols:%d rows:%d", dstfd,
wsz.ws_col, wsz.ws_row);
ioctl(dstfd, TIOCSWINSZ, &wsz);
if (!isatty(srcfd))
return;
ret = ioctl(srcfd, TIOCGWINSZ, &wsz);
if (ret < 0) {
WARN("Failed to get window size");
return;
}
ret = ioctl(dstfd, TIOCSWINSZ, &wsz);
if (ret < 0)
WARN("Failed to set window size");
else
DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
wsz.ws_row);
return;
}
static void lxc_console_winch(struct lxc_tty_state *ts)
{
lxc_console_winsz(ts->stdinfd, ts->masterfd);
if (ts->winch_proxy)
lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
}
......@@ -91,15 +105,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;
}
......@@ -107,8 +121,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;
......@@ -121,7 +136,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;
}
......@@ -133,7 +149,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;
......@@ -141,18 +157,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);
......@@ -176,7 +192,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;
......@@ -209,16 +225,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");
}
}
}
......@@ -305,7 +320,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);
......@@ -351,7 +366,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;
......@@ -463,10 +478,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;
}
......@@ -683,7 +698,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;
......@@ -709,9 +724,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;
}
}
......@@ -765,7 +780,7 @@ close_mainloop:
lxc_mainloop_close(&descr);
sigwinch_fini:
lxc_console_sigwinch_fini(ts);
lxc_console_signal_fini(ts);
close_fds:
close(masterfd);
......
......@@ -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,47 +178,47 @@ 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);
#endif
......@@ -371,7 +371,7 @@ err3:
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment