ptyfwd.c revision 4ba93280223ceb5de1bcedb196c38252f334521a
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
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringint process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering size_t in_buffer_full = 0, out_buffer_full = 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering bool tried_orderly_shutdown = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_close_ int ep = -1, signal_fd = -1;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(master >= 0);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(mask);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(kill_pid == 0 || kill_pid > 1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(signo >= 0 && signo < _NSIG);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering fd_nonblock(STDIN_FILENO, 1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering fd_nonblock(STDOUT_FILENO, 1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering fd_nonblock(master, 1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (signal_fd < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("signalfd(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering ep = epoll_create1(EPOLL_CLOEXEC);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ep < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to create epoll: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering /* We read from STDIN only if this is actually a TTY,
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering * otherwise we assume non-interactivity. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (isatty(STDIN_FILENO)) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering zero(stdin_ev);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdin_ev.events = EPOLLIN|EPOLLET;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdin_ev.data.fd = STDIN_FILENO;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to register STDIN in epoll: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering zero(stdout_ev);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdout_ev.events = EPOLLOUT|EPOLLET;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdout_ev.data.fd = STDOUT_FILENO;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering zero(master_ev);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_ev.data.fd = master;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering zero(signal_ev);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering signal_ev.events = EPOLLIN;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering signal_ev.data.fd = signal_fd;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno != EPERM) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to register stdout in epoll: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering /* stdout without epoll support. Likely redirected to regular file. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdout_writable = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to register fds in epoll: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering for (;;) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering struct epoll_event ev[16];
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering ssize_t k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering int i, nfds;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (nfds < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno == EINTR || errno == EAGAIN)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering continue;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("epoll_wait(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(nfds >= 1);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering for (i = 0; i < nfds; i++) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ev[i].data.fd == STDIN_FILENO) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ev[i].events & (EPOLLIN|EPOLLHUP))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdin_readable = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (ev[i].data.fd == STDOUT_FILENO) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ev[i].events & (EPOLLOUT|EPOLLHUP))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdout_writable = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (ev[i].data.fd == master) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ev[i].events & (EPOLLIN|EPOLLHUP))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_readable = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ev[i].events & (EPOLLOUT|EPOLLHUP))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_writable = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (ev[i].data.fd == signal_fd) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering struct signalfd_siginfo sfsi;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering ssize_t n;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering n = read(signal_fd, &sfsi, sizeof(sfsi));
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (n != sizeof(sfsi)) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (n >= 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to read from signalfd: invalid block size");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -EIO;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno != EINTR && errno != EAGAIN) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("Failed to read from signalfd: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (sfsi.ssi_signo == SIGWINCH) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering struct winsize ws;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering /* The window size changed, let's forward that. */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering ioctl(master, TIOCSWINSZ, &ws);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (sfsi.ssi_signo == SIGTERM && kill_pid > 0 && signo > 0 && !tried_orderly_shutdown) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (kill(kill_pid, signo) < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering /* This only works for systemd... */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering tried_orderly_shutdown = true;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering while ((stdin_readable && in_buffer_full <= 0) ||
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering (master_writable && in_buffer_full > 0) ||
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering (master_readable && out_buffer_full <= 0) ||
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering (stdout_writable && out_buffer_full > 0)) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (stdin_readable && in_buffer_full < LINE_MAX) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdin_readable = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("read(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering in_buffer_full += (size_t) k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (master_writable && in_buffer_full > 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering k = write(master, in_buffer, in_buffer_full);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_writable = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("write(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(in_buffer_full >= (size_t) k);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering memmove(in_buffer, in_buffer + k, in_buffer_full - k);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering in_buffer_full -= k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (master_readable && out_buffer_full < LINE_MAX) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering master_readable = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("read(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering out_buffer_full += (size_t) k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (stdout_writable && out_buffer_full > 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering k = write(STDOUT_FILENO, out_buffer, out_buffer_full);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (k < 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering stdout_writable = false;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering log_error("write(): %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -errno;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(out_buffer_full >= (size_t) k);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering memmove(out_buffer, out_buffer + k, out_buffer_full - k);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering out_buffer_full -= k;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}