Exemplo n.º 1
0
Arquivo: pty.c Projeto: myra/kmscon
void kmscon_pty_close(struct kmscon_pty *pty)
{
	if (!pty || !pty_is_open(pty))
		return;

	pty_close(pty, true);
}
Exemplo n.º 2
0
Arquivo: pty.c Projeto: myra/kmscon
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);
}
Exemplo n.º 3
0
Arquivo: pty.c Projeto: myra/kmscon
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);
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
Arquivo: pty.c Projeto: nohuhu/TuTTY
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;
}