void kmscon_pty_close(struct kmscon_pty *pty) { if (!pty || !pty_is_open(pty)) return; pty_close(pty, true); }
static void sig_child(struct ev_eloop *eloop, struct signalfd_siginfo *info, void *data) { struct kmscon_pty *pty = data; if (info->ssi_pid != pty->child) return; log_info("child exited: pid: %u status: %d utime: %llu stime: %llu", info->ssi_pid, info->ssi_status, info->ssi_utime, info->ssi_stime); pty_close(pty, false); }
static void pty_input(struct ev_fd *fd, int mask, void *data) { int ret; ssize_t len; struct kmscon_pty *pty = data; if (mask & EV_ERR) { log_warn("error on child pty socket"); goto err; } else if (mask & EV_HUP) { log_debug("child closed remote end"); goto err; } if (mask & EV_WRITEABLE) { ret = send_buf(pty); if (ret) goto err; } if (mask & EV_READABLE) { len = read(pty->fd, pty->io_buf, sizeof(pty->io_buf)); if (len > 0) { if (pty->input_cb) pty->input_cb(pty, pty->io_buf, len, pty->data); } else if (len == 0) { log_debug("child closed remote end"); goto err; } else if (errno != EWOULDBLOCK) { log_err("cannot read from pty: %m"); goto err; } } return; err: pty_close(pty, false); }
int pty_real_select_result(Pty pty, int event, int status) { char buf[4096]; int ret; int finished = FALSE; if (event < 0) { /* * We've been called because our child process did * something. `status' tells us what. */ if ((WIFEXITED(status) || WIFSIGNALED(status))) { /* * The primary child process died. We could keep * the terminal open for remaining subprocesses to * output to, but conventional wisdom seems to feel * that that's the Wrong Thing for an xterm-alike, * so we bail out now (though we don't necessarily * _close_ the window, depending on the state of * Close On Exit). This would be easy enough to * change or make configurable if necessary. */ pty->exit_code = status; pty->child_dead = TRUE; del234(ptys_by_pid, pty); finished = TRUE; } } else { if (event == 1) { ret = read(pty->master_fd, buf, sizeof(buf)); /* * Clean termination condition is that either ret == 0, or ret * < 0 and errno == EIO. Not sure why the latter, but it seems * to happen. Boo. */ if (ret == 0 || (ret < 0 && errno == EIO)) { /* * We assume a clean exit if the pty has closed but the * actual child process hasn't. The only way I can * imagine this happening is if it detaches itself from * the pty and goes daemonic - in which case the * expected usage model would precisely _not_ be for * the pterm window to hang around! */ finished = TRUE; if (!pty->child_dead) pty->exit_code = 0; } else if (ret < 0) { perror("read pty master"); exit(1); } else if (ret > 0) { from_backend(pty->frontend, 0, buf, ret); } } else if (event == 2) { /* * Attempt to send data down the pty. */ pty_try_write(pty); } } if (finished && !pty->finished) { int close_on_exit; uxsel_del(pty->master_fd); pty_close(pty); pty->master_fd = -1; pty->finished = TRUE; /* * This is a slight layering-violation sort of hack: only * if we're not closing on exit (COE is set to Never, or to * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ close_on_exit = conf_get_int(pty->conf, CONF_close_on_exit); if (close_on_exit == FORCE_OFF || (close_on_exit == AUTO && pty->exit_code != 0)) { char message[512]; message[0] = '\0'; if (WIFEXITED(pty->exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" " code %d]\r\n", WEXITSTATUS(pty->exit_code)); else if (WIFSIGNALED(pty->exit_code)) #ifdef HAVE_NO_STRSIGNAL sprintf(message, "\r\n[pterm: process terminated on signal" " %d]\r\n", WTERMSIG(pty->exit_code)); #else sprintf(message, "\r\n[pterm: process terminated on signal" " %d (%.400s)]\r\n", WTERMSIG(pty->exit_code), strsignal(WTERMSIG(pty->exit_code))); #endif from_backend(pty->frontend, 0, message, strlen(message)); } notify_remote_exit(pty->frontend); } return !finished; }
int pty_select_result(int fd, int event) { char buf[4096]; int ret; int finished = FALSE; if (fd == pty_master_fd && event == 1) { ret = read(pty_master_fd, buf, sizeof(buf)); /* * Clean termination condition is that either ret == 0, or ret * < 0 and errno == EIO. Not sure why the latter, but it seems * to happen. Boo. */ if (ret == 0 || (ret < 0 && errno == EIO)) { /* * We assume a clean exit if the pty has closed but the * actual child process hasn't. The only way I can * imagine this happening is if it detaches itself from * the pty and goes daemonic - in which case the * expected usage model would precisely _not_ be for * the pterm window to hang around! */ finished = TRUE; if (!pty_child_dead) pty_exit_code = 0; } else if (ret < 0) { perror("read pty master"); exit(1); } else if (ret > 0) { from_backend(pty_frontend, 0, buf, ret); } } else if (fd == pty_signal_pipe[0]) { pid_t pid; int status; char c[1]; read(pty_signal_pipe[0], c, 1); /* ignore its value; it'll be `x' */ do { pid = waitpid(-1, &status, WNOHANG); if (pid == pty_child_pid && (WIFEXITED(status) || WIFSIGNALED(status))) { /* * The primary child process died. We could keep * the terminal open for remaining subprocesses to * output to, but conventional wisdom seems to feel * that that's the Wrong Thing for an xterm-alike, * so we bail out now (though we don't necessarily * _close_ the window, depending on the state of * Close On Exit). This would be easy enough to * change or make configurable if necessary. */ pty_exit_code = status; pty_child_dead = TRUE; finished = TRUE; } } while(pid > 0); } if (finished && !pty_finished) { uxsel_del(pty_master_fd); pty_close(); pty_master_fd = -1; pty_finished = TRUE; /* * This is a slight layering-violation sort of hack: only * if we're not closing on exit (COE is set to Never, or to * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ if (pty_cfg.close_on_exit == FORCE_OFF || (pty_cfg.close_on_exit == AUTO && pty_exit_code != 0)) { char message[512]; if (WIFEXITED(pty_exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" " code %d]\r\n", WEXITSTATUS(pty_exit_code)); else if (WIFSIGNALED(pty_exit_code)) #ifdef HAVE_NO_STRSIGNAL sprintf(message, "\r\n[pterm: process terminated on signal" " %d]\r\n", WTERMSIG(pty_exit_code)); #else sprintf(message, "\r\n[pterm: process terminated on signal" " %d (%.400s)]\r\n", WTERMSIG(pty_exit_code), strsignal(WTERMSIG(pty_exit_code))); #endif from_backend(pty_frontend, 0, message, strlen(message)); } } return !finished; }