summary refs log blame commit diff
path: root/pkgs/applications/terminal-emulators/foot/Add-support-for-opening-an-existing-PTY.patch
blob: 5dc3b2e84607ab3fc895304c82010b996fe6d137 (plain) (tree)
































































































































































































































                                                                                                    
From 85cb6c3c705424ff3352d4771efa4c4d0dd09590 Mon Sep 17 00:00:00 2001
From: Alyssa Ross <hi@alyssa.is>
Date: Fri, 10 Dec 2021 17:40:59 +0000
Subject: [PATCH] Add support for opening an existing PTY

---
 main.c     | 13 ++++++++++-
 server.c   |  2 +-
 terminal.c | 68 ++++++++++++++++++++++++++++++++----------------------
 terminal.h |  5 ++--
 4 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/main.c b/main.c
index dffd2b2b..aa060747 100644
--- a/main.c
+++ b/main.c
@@ -3,6 +3,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <stdbool.h>
+#include <limits.h>
 #include <locale.h>
 #include <getopt.h>
 #include <signal.h>
@@ -174,6 +175,10 @@ sanitize_signals(void)
         sigaction(i, &dfl, NULL);
 }
 
+enum {
+    PTY_OPTION = CHAR_MAX + 1,
+};
+
 int
 main(int argc, char *const *argv)
 {
@@ -211,6 +216,7 @@ main(int argc, char *const *argv)
         {"maximized",              no_argument,       NULL, 'm'},
         {"fullscreen",             no_argument,       NULL, 'F'},
         {"presentation-timings",   no_argument,       NULL, 'P'}, /* Undocumented */
+        {"pty",                    required_argument, NULL, PTY_OPTION},
         {"print-pid",              required_argument, NULL, 'p'},
         {"log-level",              required_argument, NULL, 'd'},
         {"log-colorize",           optional_argument, NULL, 'l'},
@@ -223,6 +229,7 @@ main(int argc, char *const *argv)
     bool check_config = false;
     const char *conf_path = NULL;
     const char *custom_cwd = NULL;
+    const char *pty_path = NULL;
     bool as_server = false;
     const char *conf_server_socket_path = NULL;
     bool presentation_timings = false;
@@ -318,6 +325,10 @@ main(int argc, char *const *argv)
                 conf_server_socket_path = optarg;
             break;
 
+        case PTY_OPTION:
+            pty_path = optarg;
+            break;
+
         case 'P':
             presentation_timings = true;
             break;
@@ -576,7 +587,7 @@ main(int argc, char *const *argv)
         goto out;
 
     if (!as_server && (term = term_init(
-                           &conf, fdm, reaper, wayl, "foot", cwd, token,
+                           &conf, fdm, reaper, wayl, "foot", cwd, token, pty_path,
                            argc, argv, NULL,
                            &term_shutdown_cb, &shutdown_ctx)) == NULL) {
         goto out;
diff --git a/server.c b/server.c
index ca55b8f3..b1268574 100644
--- a/server.c
+++ b/server.c
@@ -332,7 +332,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
     instance->terminal = term_init(
         conf != NULL ? conf : server->conf,
         server->fdm, server->reaper, server->wayl, "footclient", cwd, token,
-        cdata.argc, argv, envp, &term_shutdown_handler, instance);
+        NULL, cdata.argc, argv, envp, &term_shutdown_handler, instance);
 
     if (instance->terminal == NULL) {
         LOG_ERR("failed to instantiate new terminal");
diff --git a/terminal.c b/terminal.c
index d4132c24..ad10bb7d 100644
--- a/terminal.c
+++ b/terminal.c
@@ -367,6 +367,7 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
         del_utmp_record(term->conf, term->reaper, term->ptmx);
         fdm_del(fdm, fd);
         term->ptmx = -1;
+        term_shutdown(term);
     }
 
     return true;
@@ -1056,11 +1057,14 @@ load_fonts_from_conf(struct terminal *term)
 static void fdm_client_terminated(
     struct reaper *reaper, pid_t pid, int status, void *data);
 
+static const int PTY_OPEN_FLAGS = O_RDWR | O_NOCTTY;
+
 struct terminal *
 term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
           struct wayland *wayl, const char *foot_exe, const char *cwd,
-          const char *token, int argc, char *const *argv, char *const *envp,
-          void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data)
+          const char *token, const char *pty_path, int argc, char *const *argv,
+          char *const *envp, void (*shutdown_cb)(void *data, int exit_code),
+          void *shutdown_data)
 {
     int ptmx = -1;
     int flash_fd = -1;
@@ -1075,7 +1079,8 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
         return NULL;
     }
 
-    if ((ptmx = posix_openpt(O_RDWR | O_NOCTTY)) < 0) {
+    ptmx = pty_path ? open(pty_path, PTY_OPEN_FLAGS) : posix_openpt(PTY_OPEN_FLAGS);
+    if (ptmx < 0) {
         LOG_ERRNO("failed to open PTY");
         goto close_fds;
     }
@@ -1142,6 +1147,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
         .fdm = fdm,
         .reaper = reaper,
         .conf = conf,
+        .slave = -1,
         .ptmx = ptmx,
         .ptmx_buffers = tll_init(),
         .ptmx_paste_buffers = tll_init(),
@@ -1272,16 +1278,18 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
 
     add_utmp_record(conf, reaper, ptmx);
 
-    /* Start the slave/client */
-    if ((term->slave = slave_spawn(
-             term->ptmx, argc, term->cwd, argv, envp, &conf->env_vars,
-             conf->term, conf->shell, conf->login_shell,
-             &conf->notifications)) == -1)
-    {
-        goto err;
-    }
+    if (!pty_path) {
+        /* Start the slave/client */
+        if ((term->slave = slave_spawn(
+                 term->ptmx, argc, term->cwd, argv, envp, &conf->env_vars,
+                 conf->term, conf->shell, conf->login_shell,
+                 &conf->notifications)) == -1)
+        {
+            goto err;
+        }
 
-    reaper_add(term->reaper, term->slave, &fdm_client_terminated, term);
+        reaper_add(term->reaper, term->slave, &fdm_client_terminated, term);
+    }
 
     /* Guess scale; we're not mapped yet, so we don't know on which
      * output we'll be. Use scaling factor from first monitor */
@@ -1541,26 +1549,30 @@ term_shutdown(struct terminal *term)
         close(term->ptmx);
 
     if (!term->shutdown.client_has_terminated) {
-        LOG_DBG("initiating asynchronous terminate of slave; "
-                "sending SIGTERM to PID=%u", term->slave);
+        if (term->slave <= 0) {
+            term->shutdown.client_has_terminated = true;
+        } else {
+            LOG_DBG("initiating asynchronous terminate of slave; "
+                    "sending SIGTERM to PID=%u", term->slave);
 
-        kill(-term->slave, SIGTERM);
+            kill(-term->slave, SIGTERM);
 
-        const struct itimerspec timeout = {.it_value = {.tv_sec = 60}};
+            const struct itimerspec timeout = {.it_value = {.tv_sec = 60}};
 
-        int timeout_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
-        if (timeout_fd < 0 ||
-            timerfd_settime(timeout_fd, 0, &timeout, NULL) < 0 ||
-            !fdm_add(term->fdm, timeout_fd, EPOLLIN, &fdm_terminate_timeout, term))
-        {
-            if (timeout_fd >= 0)
-                close(timeout_fd);
-            LOG_ERRNO("failed to create slave terminate timeout FD");
-            return false;
+            int timeout_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+            if (timeout_fd < 0 ||
+                timerfd_settime(timeout_fd, 0, &timeout, NULL) < 0 ||
+                !fdm_add(term->fdm, timeout_fd, EPOLLIN, &fdm_terminate_timeout, term))
+            {
+                if (timeout_fd >= 0)
+                    close(timeout_fd);
+                LOG_ERRNO("failed to create slave terminate timeout FD");
+                return false;
+            }
+
+            xassert(term->shutdown.terminate_timeout_fd < 0);
+            term->shutdown.terminate_timeout_fd = timeout_fd;
         }
-
-        xassert(term->shutdown.terminate_timeout_fd < 0);
-        term->shutdown.terminate_timeout_fd = timeout_fd;
     }
 
     term->selection.auto_scroll.fd = -1;
diff --git a/terminal.h b/terminal.h
index 25019ecd..569fe8f4 100644
--- a/terminal.h
+++ b/terminal.h
@@ -722,8 +722,9 @@ struct config;
 struct terminal *term_init(
     const struct config *conf, struct fdm *fdm, struct reaper *reaper,
     struct wayland *wayl, const char *foot_exe, const char *cwd,
-    const char *token, int argc, char *const *argv, char *const *envp,
-    void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data);
+    const char *token, const char *pty_path, int argc, char *const *argv,
+    char *const *envp, void (*shutdown_cb)(void *data, int exit_code),
+    void *shutdown_data);
 
 bool term_shutdown(struct terminal *term);
 int term_destroy(struct terminal *term);
-- 
2.41.0