diff --git a/slave.c b/slave.c index 92571fde..df784a7f 100644 --- a/slave.c +++ b/slave.c @@ -1,9 +1,10 @@ #define _XOPEN_SOURCE 500 #include "slave.h" #include +#include #include #include -#include +#include #include #include @@ -12,7 +13,9 @@ #define LOG_ENABLE_DBG 0 #include "log.h" -void +#include "tokenize.h" + +static void slave_exec(int ptmx, char *const argv[], int err_fd) { int pts = -1; @@ -62,3 +65,68 @@ err: close(ptmx); _exit(errno); } + +pid_t +slave_spawn(int ptmx, int argc, char *const *argv, + const char *conf_shell) +{ + int fork_pipe[2]; + if (pipe2(fork_pipe, O_CLOEXEC) < 0) { + LOG_ERRNO("failed to create pipe"); + return -1; + } + + pid_t pid = fork(); + switch (pid) { + case -1: + LOG_ERRNO("failed to fork"); + close(fork_pipe[0]); + close(fork_pipe[1]); + return -1; + + case 0: + /* Child */ + close(fork_pipe[0]); /* Close read end */ + + char **_shell_argv = NULL; + char *const *shell_argv = argv; + + if (argc == 0) { + char *shell_copy = strdup(conf_shell); + if (!tokenize_cmdline(shell_copy, &_shell_argv)) { + free(shell_copy); + (void)!write(fork_pipe[1], &errno, sizeof(errno)); + _exit(0); + } + shell_argv = _shell_argv; + } + + slave_exec(ptmx, shell_argv, fork_pipe[1]); + assert(false); + break; + + default: { + close(fork_pipe[1]); /* Close write end */ + LOG_DBG("slave has PID %d", term->slave); + + int _errno; + static_assert(sizeof(errno) == sizeof(_errno), "errno size mismatch"); + + ssize_t ret = read(fork_pipe[0], &_errno, sizeof(_errno)); + close(fork_pipe[0]); + + if (ret < 0) { + LOG_ERRNO("failed to read from pipe"); + return -1; + } else if (ret == sizeof(_errno)) { + LOG_ERRNO( + "%s: failed to execute", argc == 0 ? conf_shell : argv[0]); + return -1; + } else + LOG_DBG("%s: successfully started", conf->shell); + break; + } + } + + return pid; +} diff --git a/slave.h b/slave.h index 5ec59149..cfb18af2 100644 --- a/slave.h +++ b/slave.h @@ -1,4 +1,7 @@ #pragma once #include -void slave_exec(int ptmx, char *const argv[], int err_fd); +#include + +pid_t slave_spawn( + int ptmx, int argc, char *const *argv, const char *conf_shell); diff --git a/terminal.c b/terminal.c index 91506a39..301319ff 100644 --- a/terminal.c +++ b/terminal.c @@ -20,7 +20,6 @@ #include "vt.h" #include "selection.h" #include "config.h" -#include "tokenize.h" #include "slave.h" #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -326,6 +325,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, goto close_fds; } + /* Initialize configure-based terminal attributes */ term = malloc(sizeof(*term)); *term = (struct terminal) { .fdm = fdm, @@ -410,6 +410,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, term->cell_height = (int)ceil(term->fextents.height); LOG_INFO("cell width=%d, height=%d", term->cell_width, term->cell_height); + /* Initiailze the Wayland window backend */ if ((term->window = wayl_win_init(wayl)) == NULL) goto err; @@ -431,63 +432,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, height = max(height, term->cell_height); render_resize(term, width, height); - { - int fork_pipe[2]; - if (pipe2(fork_pipe, O_CLOEXEC) < 0) { - LOG_ERRNO("failed to create pipe"); - goto err; - } - - term->slave = fork(); - switch (term->slave) { - case -1: - LOG_ERRNO("failed to fork"); - close(fork_pipe[0]); - close(fork_pipe[1]); - goto err; - - case 0: - /* Child */ - close(fork_pipe[0]); /* Close read end */ - - char **_shell_argv = NULL; - char *const *shell_argv = argv; - - if (argc == 0) { - if (!tokenize_cmdline(conf->shell, &_shell_argv)) { - (void)!write(fork_pipe[1], &errno, sizeof(errno)); - _exit(0); - } - shell_argv = _shell_argv; - } - - slave_exec(ptmx, shell_argv, fork_pipe[1]); - assert(false); - break; - - default: { - close(fork_pipe[1]); /* Close write end */ - LOG_DBG("slave has PID %d", term->slave); - - int _errno; - static_assert(sizeof(errno) == sizeof(_errno), "errno size mismatch"); - - ssize_t ret = read(fork_pipe[0], &_errno, sizeof(_errno)); - close(fork_pipe[0]); - - if (ret < 0) { - LOG_ERRNO("failed to read from pipe"); - goto err; - } else if (ret == sizeof(_errno)) { - LOG_ERRNO( - "%s: failed to execute", argc == 0 ? conf->shell : argv[0]); - goto err; - } else - LOG_DBG("%s: successfully started", conf->shell); - break; - } - } - } + /* Start the slave/client */ + if (!slave_spawn(term->ptmx, argc, argv, conf->shell)) + goto err; /* Read logic requires non-blocking mode */ {