ptyfwd.c revision 9b15b7846d4de01bb5d9700a24077787e984e8ab
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering/***
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering This file is part of systemd.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering Copyright 2010-2013 Lennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering systemd is free software; you can redistribute it and/or modify it
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering under the terms of the GNU Lesser General Public License as published by
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering (at your option) any later version.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering systemd is distributed in the hope that it will be useful, but
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering Lesser General Public License for more details.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering You should have received a copy of the GNU Lesser General Public License
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering***/
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <sys/epoll.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <sys/signalfd.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <sys/ioctl.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <limits.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <termios.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "util.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "ptyfwd.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstruct PTYForward {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event *event;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering int master;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source *stdin_event_source;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source *stdout_event_source;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source *master_event_source;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source *sigwinch_event_source;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering struct termios saved_stdin_attr;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering struct termios saved_stdout_attr;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool saved_stdin:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool saved_stdout:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool stdin_readable:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool stdin_hangup:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool stdout_writable:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool stdout_hangup:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool master_readable:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool master_writable:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering bool master_hangup:1;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering bool repeat:1;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering bool last_char_set:1;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering char last_char;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering size_t in_buffer_full, out_buffer_full;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering usec_t escape_timestamp;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering unsigned escape_counter;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering};
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering#define ESCAPE_USEC (1*USEC_PER_SEC)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering const char *p;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(buffer);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(n > 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering for (p = buffer; p < buffer + n; p++) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* Check for ^] */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (*p == 0x1D) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering usec_t nw = now(CLOCK_MONOTONIC);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->escape_counter == 0 || nw > f->escape_timestamp + ESCAPE_USEC) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->escape_timestamp = nw;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->escape_counter = 1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering } else {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (f->escape_counter)++;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->escape_counter >= 3)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering } else {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->escape_timestamp = 0;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->escape_counter = 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return false;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic int shovel(PTYForward *f) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering ssize_t k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering while ((f->stdin_readable && f->in_buffer_full <= 0) ||
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (f->master_writable && f->in_buffer_full > 0) ||
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (f->master_readable && f->out_buffer_full <= 0) ||
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (f->stdout_writable && f->out_buffer_full > 0)) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->stdin_readable && f->in_buffer_full < LINE_MAX) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering k = read(STDIN_FILENO, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (errno == EAGAIN)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_readable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_readable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_hangup = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "read(): %m");
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_FAILURE);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else if (k == 0) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* EOF on stdin */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_readable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_hangup = true;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* Check if ^] has been
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * pressed three times within
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * one second. If we get this
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * we quite immediately. */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_FAILURE);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->in_buffer_full += (size_t) k;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->master_writable && f->in_buffer_full > 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering k = write(f->master, f->in_buffer, f->in_buffer_full);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (errno == EAGAIN || errno == EIO)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_writable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering else if (errno == EPIPE || errno == ECONNRESET) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_writable = f->master_readable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_hangup = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_event_source = sd_event_source_unref(f->master_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "write(): %m");
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_FAILURE);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f->in_buffer_full >= (size_t) k);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering memmove(f->in_buffer, f->in_buffer + k, f->in_buffer_full - k);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->in_buffer_full -= k;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->master_readable && f->out_buffer_full < LINE_MAX) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering k = read(f->master, f->out_buffer + f->out_buffer_full, LINE_MAX - f->out_buffer_full);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* Note that EIO on the master device
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * might be cause by vhangup() or
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * temporary closing of everything on
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * the other side, we treat it like
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering * EAGAIN here and try again, unless
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering * repeat is off. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering if (errno == EAGAIN || (errno == EIO && f->repeat))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_readable = false;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_readable = f->master_writable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_hangup = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_event_source = sd_event_source_unref(f->master_event_source);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering } else {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "read(): %m");
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_FAILURE);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->out_buffer_full += (size_t) k;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->stdout_writable && f->out_buffer_full > 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering k = write(STDOUT_FILENO, f->out_buffer, f->out_buffer_full);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (errno == EAGAIN)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_writable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_writable = false;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_hangup = true;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else {
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "write(): %m");
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_FAILURE);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering } else {
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering if (k > 0) {
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering f->last_char = f->out_buffer[k-1];
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering f->last_char_set = true;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering }
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f->out_buffer_full >= (size_t) k);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->out_buffer_full -= k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->stdin_hangup || f->stdout_hangup || f->master_hangup) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* Exit the loop if any side hung up and if there's
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering * nothing more to write or nothing we could write. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if ((f->out_buffer_full <= 0 || f->stdout_hangup) &&
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering (f->in_buffer_full <= 0 || f->master_hangup))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return sd_event_exit(f->event, EXIT_SUCCESS);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return 0;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic int on_master_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering PTYForward *f = userdata;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e == f->master_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd >= 0);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd == f->master);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (revents & (EPOLLIN|EPOLLHUP))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_readable = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (revents & (EPOLLOUT|EPOLLHUP))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_writable = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return shovel(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic int on_stdin_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering PTYForward *f = userdata;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e == f->stdin_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd >= 0);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd == STDIN_FILENO);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (revents & (EPOLLIN|EPOLLHUP))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdin_readable = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return shovel(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic int on_stdout_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering PTYForward *f = userdata;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e == f->stdout_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd >= 0);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(fd == STDOUT_FILENO);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (revents & (EPOLLOUT|EPOLLHUP))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_writable = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return shovel(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poetteringstatic int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *si, void *userdata) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering PTYForward *f = userdata;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering struct winsize ws;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering assert(e == f->sigwinch_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* The window size changed, let's forward that. */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
7c63b23f499069b7bbdf5e74d3e7a622918341e9Tom Gundersen (void)ioctl(f->master, TIOCSWINSZ, &ws);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poetteringint pty_forward_new(sd_event *event, int master, bool repeat, PTYForward **ret) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering _cleanup_(pty_forward_freep) PTYForward *f = NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering struct winsize ws;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f = new0(PTYForward, 1);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (!f)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return -ENOMEM;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering f->repeat = repeat;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (event)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->event = sd_event_ref(event);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering else {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_default(&f->event);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = fd_nonblock(STDIN_FILENO, true);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = fd_nonblock(STDOUT_FILENO, true);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = fd_nonblock(master, true);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master = master;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
eaf73b061604c028aa28f960870a9b46aab2f76aLuke Shumaker if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
7c63b23f499069b7bbdf5e74d3e7a622918341e9Tom Gundersen (void)ioctl(master, TIOCSWINSZ, &ws);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering struct termios raw_stdin_attr;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->saved_stdin = true;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering raw_stdin_attr = f->saved_stdin_attr;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker cfmakeraw(&raw_stdin_attr);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker }
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering struct termios raw_stdout_attr;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->saved_stdout = true;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering raw_stdout_attr = f->saved_stdout_attr;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker cfmakeraw(&raw_stdout_attr);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r < 0 && r != -EPERM)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (r == -EPERM)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering /* stdout without epoll support. Likely redirected to regular file. */
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->stdout_writable = true;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering else if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering *ret = f;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f = NULL;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return 0;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering}
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart PoetteringPTYForward *pty_forward_free(PTYForward *f) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f) {
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source_unref(f->stdin_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source_unref(f->stdout_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_source_unref(f->master_event_source);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering sd_event_unref(f->event);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->saved_stdout)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering tcsetattr(STDOUT_FILENO, TCSANOW, &f->saved_stdout_attr);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (f->saved_stdin)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering tcsetattr(STDIN_FILENO, TCSANOW, &f->saved_stdin_attr);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering free(f);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
d60473c7ba32f2325a13f0357b23fd8e25609650Lennart Poettering /* STDIN/STDOUT should not be nonblocking normally, so let's
d60473c7ba32f2325a13f0357b23fd8e25609650Lennart Poettering * unconditionally reset it */
d60473c7ba32f2325a13f0357b23fd8e25609650Lennart Poettering fd_nonblock(STDIN_FILENO, false);
d60473c7ba32f2325a13f0357b23fd8e25609650Lennart Poettering fd_nonblock(STDOUT_FILENO, false);
d60473c7ba32f2325a13f0357b23fd8e25609650Lennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poetteringint pty_forward_last_char(PTYForward *f, char *ch) {
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering assert(f);
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering assert(ch);
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering if (!f->last_char_set)
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering return -ENXIO;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering *ch = f->last_char;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering return 0;
9b15b7846d4de01bb5d9700a24077787e984e8abLennart Poettering}