ptyfwd.c revision dc75168823540076b354135f6e2de7a9a978fbca
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/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
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering bool read_only:1;
9c857b9d160c10b4454fc9f83442c1878343422fLennart 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
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering /* Continue reading after hangup? */
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering bool ignore_vhangup: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
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering /* Note that EIO on the master device
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * might be caused by vhangup() or
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * temporary closing of everything on
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * the other side, we treat it like
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * EAGAIN here and try again, unless
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * ignore_vhangup is off. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering if (errno == EAGAIN || (errno == EIO && f->ignore_vhangup))
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering f->master_readable = false;
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart 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)
679bc6cb9016715339aac4ae6b2d5371c6262935Lennart Poettering (void) ioctl(f->master, TIOCSWINSZ, &ws);
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poetteringint pty_forward_new(
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering sd_event *event,
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering int master,
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering bool ignore_vhangup,
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering bool read_only,
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering PTYForward **ret) {
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering
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
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering f->read_only = read_only;
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering f->ignore_vhangup = ignore_vhangup;
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
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (!read_only) {
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering r = fd_nonblock(STDIN_FILENO, true);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (r < 0)
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering r = fd_nonblock(STDOUT_FILENO, true);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (r < 0)
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering return r;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering }
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)
dc75168823540076b354135f6e2de7a9a978fbcaZbigniew Jędrzejewski-Szmek (void) ioctl(master, TIOCSWINSZ, &ws);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (!read_only) {
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering struct termios raw_stdin_attr;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering f->saved_stdin = true;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering raw_stdin_attr = f->saved_stdin_attr;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering cfmakeraw(&raw_stdin_attr);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering }
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering struct termios raw_stdout_attr;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering f->saved_stdout = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering raw_stdout_attr = f->saved_stdout_attr;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering cfmakeraw(&raw_stdout_attr);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (r < 0 && r != -EPERM)
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering return r;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering }
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
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering if (r < 0)
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering return r;
9c857b9d160c10b4454fc9f83442c1878343422fLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
679bc6cb9016715339aac4ae6b2d5371c6262935Lennart Poettering if (r < 0)
679bc6cb9016715339aac4ae6b2d5371c6262935Lennart Poettering return r;
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
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poetteringint pty_forward_get_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}
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poetteringint pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering int r;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering assert(f);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering if (f->ignore_vhangup == ignore_vhangup)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering return 0;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering f->ignore_vhangup = ignore_vhangup;
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering if (!f->ignore_vhangup) {
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering /* We shall now react to vhangup()s? Let's check
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering * immediately if we might be in one */
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering f->master_readable = true;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering r = shovel(f);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (r < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering return r;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering }
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering return 0;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering}
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poetteringint pty_forward_get_ignore_vhangup(PTYForward *f) {
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering assert(f);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering return f->ignore_vhangup;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering}