aboutsummaryrefslogtreecommitdiffstats
path: root/src/mds-vt.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mds-vt.c136
1 files changed, 126 insertions, 10 deletions
diff --git a/src/mds-vt.c b/src/mds-vt.c
index 8b2f276..8948c97 100644
--- a/src/mds-vt.c
+++ b/src/mds-vt.c
@@ -33,7 +33,8 @@
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
-#define reconnect_to_display() -1
+#define reconnect_fd_to_display(fd) -1
+#define reconnect_to_display() reconnect_fd_to_display(&socket_fd)
@@ -104,6 +105,26 @@ static volatile sig_atomic_t switching_vt = 0;
*/
static char vtfile_path[PATH_MAX];
+/**
+ * The file descriptor for the secondary connection to the display
+ */
+static int secondary_socket_fd;
+
+/**
+ * Whether the secondary thread has been started
+ */
+static int secondary_thread_started = 0;
+
+/**
+ * The secondary thread
+ */
+static pthread_t secondary_thread;
+
+/**
+ * Whether the secondary thread failed
+ */
+static volatile sig_atomic_t secondary_thread_failed = 0;
+
/**
@@ -186,6 +207,7 @@ int initialise_server(void)
{
struct vt_mode mode;
char* display_env;
+ int primary_socket_fd;
const char* const message =
"Command: intercept\n"
"Message ID: 0\n"
@@ -193,6 +215,19 @@ int initialise_server(void)
"\n"
"Command: get-vt\n"
"Command: configure-vt\n";
+ const char* const secondary_message =
+ "Command: intercept\n"
+ "Message ID: 0\n"
+ "Priority: -4611686018427387904\n" /* −2⁶² */
+ "Length: 22\n"
+ "\n"
+ "Command: switching-vt\n";
+
+ primary_socket_fd = socket_fd;
+ if (connect_to_display())
+ return 1;
+ secondary_socket_fd = socket_fd;
+ socket_fd = primary_socket_fd;
display_env = getenv("MDS_DISPLAY");
display_env = display_env ? strchr(display_env, ':') : NULL;
@@ -223,7 +258,9 @@ int initialise_server(void)
fail_if (vt_is_active < 0);
}
- if (full_send(message, strlen(message)))
+ if (full_send(secondary_socket_fd, secondary_message, strlen(secondary_message)))
+ return 1;
+ if (full_send(socket_fd, message, strlen(message)))
return 1;
fail_if (server_initialised() < 0);
fail_if (mds_message_initialise(&received));
@@ -267,6 +304,10 @@ int postinitialise_server(void)
return 1;
}
connected = 1;
+
+ if ((errno = pthread_create(&secondary_thread, NULL, secondary_loop, NULL)))
+ return 1;
+
return 0;
}
@@ -281,7 +322,7 @@ int postinitialise_server(void)
*/
size_t marshal_server_size(void)
{
- size_t rc = 5 * sizeof(int) + sizeof(uint32_t);
+ size_t rc = 6 * sizeof(int) + sizeof(uint32_t);
rc += sizeof(struct stat);
rc += PATH_MAX * sizeof(char);
rc += mds_message_marshal_size(&received);
@@ -304,6 +345,7 @@ int marshal_server(char* state_buf)
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);
+ buf_set_next(state_buf, int, secondary_socket_fd);
memcpy(state_buf, vtfile_path, PATH_MAX * sizeof(char));
state_buf += PATH_MAX;
mds_message_marshal(&received, state_buf);
@@ -334,6 +376,7 @@ int unmarshal_server(char* state_buf)
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);
+ buf_set_next(state_buf, int, secondary_socket_fd);
memcpy(vtfile_path, state_buf, PATH_MAX * sizeof(char));
state_buf += PATH_MAX;
r = mds_message_unmarshal(&received, state_buf);
@@ -391,7 +434,7 @@ int master_loop(void)
else if (errno != ECONNRESET)
goto pfail;
- eprint("lost connection to server.");
+ eprint("lost primary connection to server.");
mds_message_destroy(&received);
mds_message_initialise(&received);
connected = 0;
@@ -410,13 +453,69 @@ int master_loop(void)
pfail:
xperror(*argv);
fail:
+ rc |= secondary_thread_failed;
if (rc || !reexecing)
mds_message_destroy(&received);
+ if ((errno = pthread_join(secondary_thread, NULL)))
+ xperror(*argv);
return rc;
}
/**
+ * Wait for confirmation that we may switch virtual terminal
+ *
+ * @param data Thread input parameter, will always be `NULL`
+ * @return Thread return value, will always be `NULL`
+ */
+void* secondary_loop(void* data)
+{
+ mds_message_t secondary_received;
+ int r;
+ (void) data;
+
+ secondary_thread_started = 1;
+ fail_if (mds_message_initialise(&secondary_received) < 0);
+
+ while (!reexecing && !terminating)
+ {
+ if (r = mds_message_read(&secondary_received, secondary_socket_fd), r == 0)
+ r = vt_accept_switch(display_tty_fd);
+ if (r == 0)
+ continue;
+
+ if (r == -2)
+ {
+ eprint("corrupt message received, aborting.");
+ goto fail;
+ }
+ else if (errno == EINTR)
+ continue;
+ else if (errno != ECONNRESET)
+ goto pfail;
+
+ eprint("lost secondary connection to server.");
+ mds_message_destroy(&secondary_received);
+ mds_message_initialise(&secondary_received);
+ if (reconnect_fd_to_display(&secondary_socket_fd) < 0)
+ goto fail;
+ }
+
+ goto done;
+ pfail:
+ xperror(*argv);
+ fail:
+ secondary_thread_failed = 1;
+ done:
+ secondary_thread_started = 0;
+ mds_message_destroy(&secondary_received);
+ if (!reexecing && !terminating)
+ pthread_kill(master_thread, SIGTERM);
+ return NULL;
+}
+
+
+/**
* Perform a VT switch requested by the OS kernel
*
* @param leave_foreground Whether the display is leaving the foreground
@@ -436,7 +535,7 @@ int switch_vt(int leave_foreground)
message_id = message_id == UINT32_MAX ? 0 : (message_id + 1);
- return -!!full_send(buf, strlen(buf));
+ return -!!full_send(socket_fd, buf, strlen(buf));
}
@@ -535,7 +634,7 @@ int handle_get_vt(const char* client, const char* message)
message_id = message_id == UINT32_MAX ? 0 : (message_id + 1);
- r = full_send(buf, strlen(buf));
+ r = full_send(socket_fd, buf, strlen(buf));
return ((active < 0) || r) ? -1 : 0;
}
@@ -571,7 +670,23 @@ int handle_configure_vt(const char* client, const char* message, const char* gra
message_id = message_id == UINT32_MAX ? 0 : (message_id + 1);
- return -!!full_send(buf, strlen(buf));
+ return -!!full_send(socket_fd, buf, strlen(buf));
+}
+
+
+/**
+ * Send a singal to all threads except the current thread
+ *
+ * @param signo The signal
+ */
+void signal_all(int signo)
+{
+ pthread_t current_thread = pthread_self();
+
+ if (pthread_equal(current_thread, master_thread) == 0)
+ pthread_kill(master_thread, signo);
+ else if (secondary_thread_started)
+ pthread_kill(secondary_thread, signo);
}
@@ -591,17 +706,18 @@ void received_switch_vt(int signo)
/**
* Send a full message even if interrupted
*
+ * @param socket The file descriptor for the socket to use
* @param message The message to send
* @param length The length of the message
- * @return Non-zero on success
+ * @return Zero on success, -1 on error
*/
-int full_send(const char* message, size_t length)
+int full_send(int socket, const char* message, size_t length)
{
size_t sent;
while (length > 0)
{
- sent = send_message(socket_fd, message, length);
+ sent = send_message(socket, message, length);
if (sent > length)
{
eprint("Sent more of a message than exists in the message, aborting.");