diff options
-rw-r--r-- | src/mds-vt.c | 125 | ||||
-rw-r--r-- | src/mds-vt.h | 10 |
2 files changed, 130 insertions, 5 deletions
diff --git a/src/mds-vt.c b/src/mds-vt.c index a6124c9..bb86101 100644 --- a/src/mds-vt.c +++ b/src/mds-vt.c @@ -17,6 +17,7 @@ */ #include "mds-vt.h" +#include <libmdsserver/config.h> #include <libmdsserver/macros.h> #include <libmdsserver/util.h> #include <libmdsserver/mds-message.h> @@ -28,7 +29,7 @@ #include <stdlib.h> #include <sys/ioctl.h> #include <linux/kd.h> -#include <sys/stat.h> +#include <limits.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> @@ -73,6 +74,36 @@ static mds_message_t received; */ static int connected = 1; +/** + * The index of the VT used for the display + */ +static int display_vt; + +/** + * The file descriptor the display's TTY is opened on + */ +static int display_tty_fd = -1; + +/** + * Whether the display's TTY is in the foreground + */ +static int vt_is_active = 1; + +/** + * The stat for the TTY of the display's VT before we toke it + */ +static struct stat old_vt_stat; + +/** + * -1 if switching to our VT, 1 if switching to another VT, 0 otherwise + */ +static volatile int switching_vt = 0; + +/** + * The pathname for the file containing VT information + */ +static char vtfile_path[PATH_MAX]; + /** @@ -95,22 +126,67 @@ int __attribute__((const)) preinitialise_server(void) */ int initialise_server(void) { + struct vt_mode mode; + char* display_env; const char* const message = "Command: intercept\n" "Message ID: 0\n" "Length: 38\n" "\n" - "Command: get-vt\n"; + "Command: get-vt\n" "Command: configure-vt\n"; + display_env = getenv("MDS_DISPLAY"); + display_env = display_env ? strchr(display_env, ':') : NULL; + if ((display_env == NULL) || (strlen(display_env) < 2)) + goto no_display; + + memset(vtfile_path, 0, sizeof(vtfile_path)); + xsnprintf(vtfile_path, "%s/%s.vt", MDS_RUNTIME_ROOT_DIRECTORY, display_env + 1); + + if (is_respawn == 0) + { + display_vt = vt_get_next_available(); + if (display_vt == 0) + { + eprint("out of available virtual terminals, I am stymied."); + goto fail; + } + else if (display_vt < 0) + goto pfail; + display_tty_fd = vt_open(display_vt, &old_vt_stat); + /* TODO write display_vt and old_vt_stat to vtfile_path */ + fail_if (vt_set_active(display_vt) < 0); + } + else + { + /* TODO read display_vt and old_vt_stat from vtfile_path */ + vt_is_active = (display_vt == vt_get_active()); + fail_if (vt_is_active < 0); + } + if (full_send(message, strlen(message))) return 1; fail_if (server_initialised() < 0); fail_if (mds_message_initialise(&received)); + fail_if (xsigaction(SIGRTMIN + 1, received_switch_vt) < 0); + fail_if (xsigaction(SIGRTMIN + 2, received_switch_vt) < 0); + vt_construct_mode(1, SIGRTMIN + 1, SIGRTMIN + 2, &mode); + fail_if (vt_get_set_mode(display_tty_fd, 1, &mode) < 0); + if (vt_set_exclusive(display_tty_fd, 1) < 0) + xperror(*argv); + return 0; + no_display: + eprint("no display has been set, how did this happen."); + return 1; pfail: xperror(*argv); + fail: + unlink(vtfile_path); + if (display_tty_fd >= 0) + vt_close(display_tty_fd, &old_vt_stat); mds_message_destroy(&received); return 1; } @@ -147,7 +223,11 @@ int postinitialise_server(void) */ size_t marshal_server_size(void) { - return 2 * sizeof(int) + sizeof(int32_t) + mds_message_marshal_size(&received); + size_t rc = 5 * sizeof(int) + sizeof(int32_t); + rc += sizeof(struct stat); + rc += sizeof(vtfile_path); + rc += mds_message_marshal_size(&received); + return rc; } @@ -162,6 +242,12 @@ int marshal_server(char* state_buf) buf_set_next(state_buf, int, MDS_VT_VARS_VERSION); buf_set_next(state_buf, int, connected); buf_set_next(state_buf, int32_t, message_id); + buf_set_next(state_buf, int, display_vt); + buf_set_next(state_buf, int, display_tty_fd); + buf_set_next(state_buf, int, vt_is_active); + buf_set_next(state_buf, struct stat, old_vt_stat); + memcpy(state_buf, vtfile_path, PATH_MAX * sizeof(char)); + state_buf += PATH_MAX; mds_message_marshal(&received, state_buf); mds_message_destroy(&received); @@ -186,6 +272,12 @@ int unmarshal_server(char* state_buf) buf_next(state_buf, int, 1); buf_get_next(state_buf, int, connected); buf_get_next(state_buf, int32_t, message_id); + buf_get_next(state_buf, int, display_vt); + buf_get_next(state_buf, int, display_tty_fd); + buf_get_next(state_buf, int, vt_is_active); + buf_get_next(state_buf, struct stat, old_vt_stat); + memcpy(vtfile_path, state_buf, PATH_MAX * sizeof(char)); + state_buf += PATH_MAX; r = mds_message_unmarshal(&received, state_buf); if (r) { @@ -215,11 +307,16 @@ int __attribute__((const)) reexec_failure_recover(void) */ int master_loop(void) { - int rc = 1; + int rc = 1, r; while (!reexecing && !terminating) { - int r = mds_message_read(&received, socket_fd); + if (switching_vt) + { + /* FIXME */ + } + + r = mds_message_read(&received, socket_fd); if (r == 0) { r = 0; /* FIXME */ @@ -247,6 +344,11 @@ int master_loop(void) } rc = 0; + if (vt_set_exclusive(display_tty_fd, 0) < 0) xperror(*argv); + if (vt_set_graphical(display_tty_fd, 0) < 0) xperror(*argv); + if (unlink(vtfile_path) < 0) + xperror(*argv); + vt_close(display_tty_fd, &old_vt_stat); goto fail; pfail: xperror(*argv); @@ -258,6 +360,19 @@ int master_loop(void) /** + * This function is called when the kernel wants + * to switch foreground virtual terminal + * + * @param signo The received signal number + */ +void received_switch_vt(int signo) +{ + int leaving = signo == (SIGRTMIN + 1); + switching_vt = leaving ? 1 : -1; +} + + +/** * Send a full message even if interrupted * * @param message The message to send diff --git a/src/mds-vt.h b/src/mds-vt.h index 60204fc..55057c3 100644 --- a/src/mds-vt.h +++ b/src/mds-vt.h @@ -21,10 +21,20 @@ #include "mds-base.h" +#include <sys/stat.h> #include <linux/vt.h> /** + * This function is called when the kernel wants + * to switch foreground virtual terminal + * + * @param signo The received signal number + */ +void received_switch_vt(int signo); + + +/** * Send a full message even if interrupted * * @param message The message to send |