subterm.c revision 5ab887e98d80ffaf05a97abe4cdc1553a85f0637
d657c51f14601d0235434ffb78cf6ac0f27cc83cLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
220a21d38f675eb835f5758e3d23e896573aa5eaLennart Poettering/***
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann This file is part of systemd.
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering systemd is free software; you can redistribute it and/or modify it
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering (at your option) any later version.
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering systemd is distributed in the hope that it will be useful, but
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Lesser General Public License for more details.
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering You should have received a copy of the GNU Lesser General Public License
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering***/
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering/*
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * Stacked Terminal-Emulator
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * This is an interactive test of the term_screen implementation. It runs a
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * fully-fletched terminal-emulator inside of a parent TTY. That is, instead of
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * rendering the terminal as X11-window, it renders it as sub-window in the
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * parent TTY. Think of this like what "GNU-screen" does.
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering */
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <assert.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <errno.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <stdarg.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <stdbool.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <stdio.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <stdlib.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <string.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <sys/ioctl.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include <termios.h>
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "macro.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "pty.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "ring.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "sd-event.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "term-internal.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#include "util.h"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringtypedef struct Output Output;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringtypedef struct Terminal Terminal;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstruct Output {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int fd;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int width;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int height;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int in_width;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int in_height;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int cursor_x;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering unsigned int cursor_y;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering char obuf[4096];
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering size_t n_obuf;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering bool resized : 1;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering bool in_menu : 1;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering};
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstruct Terminal {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering sd_event *event;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering sd_event_source *frame_timer;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Output *output;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering term_utf8 utf8;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering term_parser *parser;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering term_screen *screen;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int in_fd;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int out_fd;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering struct termios saved_in_attr;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering struct termios saved_out_attr;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Pty *pty;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Ring out_ring;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering bool is_scheduled : 1;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering bool is_dirty : 1;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering bool is_menu : 1;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering};
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering/*
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering * Output Handling
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering */
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_HORIZ "\xe2\x94\x81"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_VERT "\xe2\x94\x83"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_VERT_RIGHT "\xe2\x94\xa3"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_VERT_LEFT "\xe2\x94\xab"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_DOWN_RIGHT "\xe2\x94\x8f"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_DOWN_LEFT "\xe2\x94\x93"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_UP_RIGHT "\xe2\x94\x97"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering#define BORDER_UP_LEFT "\xe2\x94\x9b"
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_winch(Output *o) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering struct winsize wsz = { };
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int r;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(o, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = ioctl(o->fd, TIOCGWINSZ, &wsz);
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann if (r < 0) {
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering log_error("error: cannot read window-size: %m");
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering return -errno;
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering }
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering if (wsz.ws_col != o->width || wsz.ws_row != o->height) {
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering o->width = wsz.ws_col;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann o->height = wsz.ws_row;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann o->in_width = MAX(o->width, 2U) - 2;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann o->in_height = MAX(o->height, 6U) - 6;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann o->resized = true;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann }
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann return 0;
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann}
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann
ec5249a27adb1ffbcd41f2c771e19c3353819456Daniel Mackstatic int output_flush(Output *o) {
ec5249a27adb1ffbcd41f2c771e19c3353819456Daniel Mack ssize_t len;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (o->n_obuf < 1)
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering len = loop_write(o->fd, o->obuf, o->n_obuf, false);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (len < 0) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return len;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering }
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering o->n_obuf = 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering}
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_write(Output *o, const void *buf, size_t size) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering ssize_t len;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int r;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(o, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(buf || size < 1, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (size < 1)
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (o->n_obuf + size > o->n_obuf && o->n_obuf + size <= sizeof(o->obuf)) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering memcpy(o->obuf + o->n_obuf, buf, size);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering o->n_obuf += size;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering }
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = output_flush(o);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (r < 0)
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return r;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering len = loop_write(o->fd, buf, size, false);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (len < 0) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return len;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering }
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return 0;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering}
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_vnprintf(Output *o, size_t max, const char *format, va_list args) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering char buf[4096];
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int r;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(o, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(format, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(max <= sizeof(buf), -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = vsnprintf(buf, max, format, args);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (r > (ssize_t)max)
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = max;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return output_write(o, buf, r);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering}
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_nprintf(Output *o, size_t max, const char *format, ...) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering va_list args;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering int r;
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering va_start(args, format);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = output_vnprintf(o, max, format, args);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering va_end(args);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering return r;
e1439a1472c5f691733b8ef10e702beac2496a63David Herrmann}
e1439a1472c5f691733b8ef10e702beac2496a63David Herrmann
ec5249a27adb1ffbcd41f2c771e19c3353819456Daniel Mackstatic int output_vprintf(Output *o, const char *format, va_list args) {
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann char buf[4096];
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann int r;
10fa421cd2abdc2ae1a07f7c13bfaa4ee6d6de4fDavid Herrmann
10fa421cd2abdc2ae1a07f7c13bfaa4ee6d6de4fDavid Herrmann assert_return(o, -EINVAL);
10fa421cd2abdc2ae1a07f7c13bfaa4ee6d6de4fDavid Herrmann assert_return(format, -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = vsnprintf(buf, sizeof(buf), format, args);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering
10fa421cd2abdc2ae1a07f7c13bfaa4ee6d6de4fDavid Herrmann assert_return(r < (ssize_t)sizeof(buf), -ENOBUFS);
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann return output_write(o, buf, r);
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann}
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmannstatic int output_printf(Output *o, const char *format, ...) {
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmann va_list args;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann int r;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann va_start(args, format);
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann r = output_vprintf(o, format, args);
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann va_end(args);
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann return r;
01608bc86a104423d192364f9534b83d0c75db7fKay Sievers}
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmannstatic int output_move_to(Output *o, unsigned int x, unsigned int y) {
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann int r;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann assert_return(o, -EINVAL);
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack /* force the \e[H code as o->cursor_x/y might be out-of-date */
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack
37d54b938faeefd0a5a74f9197a33d78bbb8d6bfDaniel Mack r = output_printf(o, "\e[%u;%uH", y + 1, x + 1);
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack if (r < 0)
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack return r;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack o->cursor_x = x;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack o->cursor_y = y;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack return 0;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack}
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mackstatic int output_print_line(Output *o, size_t len) {
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack const char line[] =
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ BORDER_HORIZ;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack const size_t max = (sizeof(line) - 1) / (sizeof(BORDER_HORIZ) - 1);
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack size_t i;
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack int r = 0;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
f5f113f66692abaf72e83698cb7b4f3690b90cf8David Herrmann assert_return(o, -EINVAL);
f5f113f66692abaf72e83698cb7b4f3690b90cf8David Herrmann
f5f113f66692abaf72e83698cb7b4f3690b90cf8David Herrmann for ( ; len > 0; len -= i) {
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann i = (len > max) ? max : len;
01608bc86a104423d192364f9534b83d0c75db7fKay Sievers r = output_write(o, line, i * (sizeof(BORDER_HORIZ) - 1));
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann if (r < 0)
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann break;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann }
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann return r;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann}
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmannstatic int output_frame_printl(Output *o, const char *format, ...) {
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann va_list args;
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann int r;
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann assert(o);
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann assert(format);
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann /* out of frame? */
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann if (o->cursor_y < 3 || o->cursor_y >= o->height - 3)
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann return 0;
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann va_start(args, format);
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann r = output_vnprintf(o, o->width - 2, format, args);
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann va_end(args);
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmann
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann if (r < 0)
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann return r;
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sievers
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sievers return output_move_to(o, 1, o->cursor_y + 1);
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sievers}
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sievers
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sieversstatic Output *output_free(Output *o) {
861b02ebd6ec997a6880824960ba8903bac74f7dKay Sievers if (!o)
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann return NULL;
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann /* disable alternate screen buffer */
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann output_printf(o, "\e[?1049l");
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann output_flush(o);
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann /* o->fd is owned by the caller */
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann free(o);
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann return NULL;
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann}
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mackstatic int output_new(Output **out, int fd) {
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack Output *o;
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack int r;
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack assert_return(out, -EINVAL);
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack
9b361114f568e839784a3aeba5c1df5a95e86832Daniel Mack o = new0(Output, 1);
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann if (!o)
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann return log_oom();
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann o->fd = fd;
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann
5541c88977e63215e74b7517fb33cb27e5a04f17David Herrmann r = output_winch(o);
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann if (r < 0)
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann goto error;
2d1ca11270e66777c90a449096203afebc37ec9cDavid Herrmann
2d1ca11270e66777c90a449096203afebc37ec9cDavid Herrmann /* enable alternate screen buffer */
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann r = output_printf(o, "\e[?1049h");
2d1ca11270e66777c90a449096203afebc37ec9cDavid Herrmann if (r < 0)
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann goto error;
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pitt
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pitt r = output_flush(o);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering if (r < 0)
5f92d24fa85d6652c4754e3b3b2a3393026bd0b9Kay Sievers goto error;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering *out = o;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering return 0;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poetteringerror:
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_free(o);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering return r;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering}
5f92d24fa85d6652c4754e3b3b2a3393026bd0b9Kay Sievers
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pittstatic void output_draw_frame(Output *o) {
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering unsigned int i;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering assert(o);
c65514649680e5d5ee6a118db6e5b20438cb1710Ronny Chevalier
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print header-frame */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, BORDER_DOWN_RIGHT);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_print_line(o, o->width - 2);
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_printf(o, BORDER_DOWN_LEFT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n"
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pitt "\e[2;%uH" /* cursor-position: 2/x */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n"
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT_RIGHT,
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering o->width);
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_print_line(o, o->width - 2);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, BORDER_VERT_LEFT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n");
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print body-frame */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering for (i = 0; i < o->in_height; ++i) {
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, BORDER_VERT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\e[%u;%uH" /* cursor-position: 2/x */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n",
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering i + 4, o->width);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering }
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print footer-frame */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, BORDER_VERT_RIGHT);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_print_line(o, o->width - 2);
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_printf(o, BORDER_VERT_LEFT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n"
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\e[%u;%uH" /* cursor-position: 2/x */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_VERT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering "\r\n"
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering BORDER_UP_RIGHT,
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering o->height - 1, o->width);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_print_line(o, o->width - 2);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, BORDER_UP_LEFT);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print header/footer text */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, "\e[2;3H");
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_nprintf(o, o->width - 4, "systemd - embedded terminal emulator");
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_printf(o, "\e[%u;3H", o->height - 1);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering output_nprintf(o, o->width - 4, "press ^C to enter menu");
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering}
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poetteringstatic void output_draw_menu(Output *o) {
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering assert(o);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, "");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, " Menu: (the following keys are recognized)");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, " q: quit");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, " ^C: send ^C to the PTY");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering}
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poetteringstatic void output_draw_screen(Output *o, term_screen *s) {
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pitt unsigned int i, j;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering bool first = true;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann assert(o);
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann assert(s);
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann for (j = 0; j < s->page->height && j < o->in_height; ++j) {
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann if (!first)
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann output_printf(o, "\e[m\r\n" BORDER_VERT);
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann first = false;
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann for (i = 0; i < s->page->width && i < o->in_width; ++i) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering term_charbuf_t buf;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering term_cell *cell = &s->page->lines[j]->cells[i];
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering size_t k, len, ulen;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering const uint32_t *str;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering char utf8[4];
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering switch (cell->attr.fg.ccode) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_DEFAULT:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[39m");
29d1fcb4a3c921a3d4490353474e9775f7b13b0eZbigniew Jędrzejewski-Szmek break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_256:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[38;5;%um", cell->attr.fg.c256);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_RGB:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[38;2;%u;%u;%um", cell->attr.fg.red, cell->attr.fg.green, cell->attr.fg.blue);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_BLACK ... TERM_CCODE_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (cell->attr.bold)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 90);
29d1fcb4a3c921a3d4490353474e9775f7b13b0eZbigniew Jędrzejewski-Szmek else
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 30);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_LIGHT_BLACK + 90);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering switch (cell->attr.bg.ccode) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_DEFAULT:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[49m");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_256:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[48;5;%um", cell->attr.bg.c256);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_RGB:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[48;2;%u;%u;%um", cell->attr.bg.red, cell->attr.bg.green, cell->attr.bg.blue);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_BLACK ... TERM_CCODE_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_BLACK + 40);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering case TERM_CCODE_LIGHT_BLACK ... TERM_CCODE_LIGHT_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_LIGHT_BLACK + 100);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering break;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%u;%u;%u;%u;%u;%um",
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.bold ? 1 : 22,
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.italic ? 3 : 23,
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.underline ? 4 : 24,
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.inverse ? 7 : 27,
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.blink ? 5 : 25,
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering cell->attr.hidden ? 8 : 28);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering str = term_char_resolve(cell->ch, &len, &buf);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering if (len < 1) {
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering output_printf(o, " ");
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering } else {
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering for (k = 0; k < len; ++k) {
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering ulen = term_utf8_encode(utf8, str[k]);
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering output_write(o, utf8, ulen);
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering }
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering }
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering }
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering }
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering output_move_to(o, s->cursor_x + 1, s->cursor_y + 3);
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering output_printf(o, "\e[m");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering}
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic void output_draw(Output *o, bool menu, term_screen *screen) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering assert(o);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /*
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * This renders the contenst of the terminal. The layout contains a
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * header, the main body and a footer. Around all areas we draw a
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * border. It looks something like this:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering *
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | Header |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | Body |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * ~ ~
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * ~ ~
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * | Footer |
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering *
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * The body is the part that grows vertically.
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering *
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * We need at least 6 vertical lines to render the screen. This would
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * leave 0 lines for the body. Therefore, we require 7 lines so there's
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * at least one body line. Similarly, we need 2 horizontal cells for the
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * frame, so we require 3.
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * If the window is too small, we print an error message instead.
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (o->in_width < 1 || o->in_height < 1) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[2J" /* erase-in-display: whole screen */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering "\e[H"); /* cursor-position: home */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "error: screen too small, need at least 3x7 cells");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_flush(o);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering return;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* hide cursor */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[?25l");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* frame-content is contant; only resizes can change it */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (o->resized || o->in_menu != menu) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[2J" /* erase-in-display: whole screen */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering "\e[H"); /* cursor-position: home */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_draw_frame(o);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering o->resized = false;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering o->in_menu = menu;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* move cursor to child's position */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_move_to(o, 1, 3);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (menu)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_draw_menu(o);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering else
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_draw_screen(o, screen);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* show cursor */
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[?25h");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /*
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * Hack: sd-term was not written to support TTY as output-objects, thus
1a2d5fbe7efa04181a2d5518bc510b84b280baf9David Herrmann * expects callers to use term_screen_feed_keyboard(). However, we
1a2d5fbe7efa04181a2d5518bc510b84b280baf9David Herrmann * forward TTY input directly. Hence, we're not notified about keypad
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * changes. Update the related modes djring redraw to keep them at least
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * in sync.
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (screen->flags & TERM_FLAG_CURSOR_KEYS)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[?1h");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering else
1a2d5fbe7efa04181a2d5518bc510b84b280baf9David Herrmann output_printf(o, "\e[?1l");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (screen->flags & TERM_FLAG_KEYPAD_MODE)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e=");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering else
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e>");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_flush(o);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering}
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering/*
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * Terminal Handling
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic void terminal_dirty(Terminal *t) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering uint64_t usec;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering int r;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering assert(t);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (t->is_scheduled) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering t->is_dirty = true;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering return;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* 16ms timer */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_now(t->event, CLOCK_MONOTONIC, &usec);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering assert(r >= 0);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering usec += 16 * USEC_PER_MSEC;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_source_set_time(t->frame_timer, usec);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (r >= 0) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_source_set_enabled(t->frame_timer, SD_EVENT_ONESHOT);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (r >= 0)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering t->is_scheduled = true;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering t->is_dirty = false;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_draw(t->output, t->is_menu, t->screen);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering}
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic int terminal_frame_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering Terminal *t = userdata;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering t->is_scheduled = false;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (t->is_dirty)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering terminal_dirty(t);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering return 0;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering}
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic int terminal_winch_fn(sd_event_source *source, const struct signalfd_siginfo *ssi, void *userdata) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering Terminal *t = userdata;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering int r;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_winch(t->output);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (t->pty) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = pty_resize(t->pty, t->output->in_width, t->output->in_height);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (r < 0)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering log_error("error: pty_resize() (%d): %s", r, strerror(-r));
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering }
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (r < 0)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering terminal_dirty(t);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering return 0;
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering}
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering
39315f9f8dd5a16b4561c5efffc6114c75835011Lennart Poetteringstatic int terminal_push_tmp(Terminal *t, uint32_t ucs4) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering char buf[4];
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering size_t len;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering assert(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering len = term_utf8_encode(buf, ucs4);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (len < 1)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = ring_push(&t->out_ring, buf, len);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_oom();
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_write_tmp(Terminal *t) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering struct iovec vec[2];
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering size_t num, i;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering assert(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering num = ring_peek(&t->out_ring, vec);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (num < 1)
7edecf218e5884ec8d1549707b4c7a0572c2d93bThomas Hindoe Paaboel Andersen return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (t->pty) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering for (i = 0; i < num; ++i) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = pty_write(t->pty, vec[i].iov_base, vec[i].iov_len);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: cannot write to PTY (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering ring_flush(&t->out_ring);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic void terminal_discard_tmp(Terminal *t) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering assert(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering ring_flush(&t->out_ring);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_menu(Terminal *t, const term_seq *seq) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering switch (seq->type) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case TERM_SEQ_IGNORE:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case TERM_SEQ_GRAPHIC:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering switch (seq->terminator) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case 'q':
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering sd_event_exit(t->event, 0);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case TERM_SEQ_CONTROL:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering switch (seq->terminator) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case 0x03:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_push_tmp(t, 0x03);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_write_tmp(t);
94e5ba370aa12b47571f08112986d0b91935dee9Torstein Husebø break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t->is_menu = false;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_dirty(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering Terminal *t = userdata;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering char buf[4096];
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering ssize_t len, i;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r, type;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering len = read(fd, buf, sizeof(buf));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (len < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (errno == EAGAIN || errno == EINTR)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: cannot read from TTY (%d): %m", -errno);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return -errno;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering for (i = 0; i < len; ++i) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering const term_seq *seq;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering const uint32_t *str;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering size_t n_str, j;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering str = term_utf8_decode(&t->utf8, &n_str, buf[i]);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering for (j = 0; j < n_str; ++j) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering type = term_parser_feed(t->parser, &seq, str[j]);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (type < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: term_parser_feed() (%d): %s", type, strerror(-type));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return type;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (!t->is_menu) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = terminal_push_tmp(t, str[j]);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (type == TERM_SEQ_NONE) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering /* We only intercept one-char sequences, so in
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * case term_parser_feed() couldn't parse a
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * sequence, it is waiting for more data. We
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * know it can never be a one-char sequence
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * then, so we can safely forward the data.
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * This avoids withholding ESC or other values
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * that may be one-shot depending on the
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering * application. */
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = terminal_write_tmp(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering } else if (t->is_menu) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = terminal_menu(t, seq);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering } else if (seq->type == TERM_SEQ_CONTROL && seq->terminator == 0x03) { /* ^C opens the menu */
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_discard_tmp(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t->is_menu = true;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_dirty(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering } else {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = terminal_write_tmp(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering Terminal *t = userdata;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering switch (event) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case PTY_CHILD:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering sd_event_exit(t->event, 0);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering case PTY_DATA:
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = term_screen_feed_text(t->screen, ptr, size);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: term_screen_feed_text() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
94e5ba370aa12b47571f08112986d0b91935dee9Torstein Husebø
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering terminal_dirty(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering break;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_write_fn(term_screen *screen, void *userdata, const void *buf, size_t size) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering Terminal *t = userdata;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (!t->pty)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = ring_push(&t->out_ring, buf, size);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_oom();
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_cmd_fn(term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return 0;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic Terminal *terminal_free(Terminal *t) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (!t)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return NULL;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering ring_clear(&t->out_ring);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering term_screen_unref(t->screen);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering term_parser_free(t->parser);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering output_free(t->output);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering sd_event_source_unref(t->frame_timer);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering sd_event_unref(t->event);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering tcsetattr(t->in_fd, TCSANOW, &t->saved_in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering tcsetattr(t->out_fd, TCSANOW, &t->saved_out_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering free(t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return NULL;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering}
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_new(Terminal **out, int in_fd, int out_fd) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering struct termios in_attr, out_attr;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering Terminal *t;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering int r;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering assert_return(out, -EINVAL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = tcgetattr(in_fd, &in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcgetattr() (%d): %m", -errno);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return -errno;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = tcgetattr(out_fd, &out_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcgetattr() (%d): %m", -errno);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return -errno;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
dd2fd155901a965ec0efa3adc460b33d2048d4c2Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t = new0(Terminal, 1);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (!t)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering return log_oom();
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t->in_fd = in_fd;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t->out_fd = out_fd;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering memcpy(&t->saved_in_attr, &in_attr, sizeof(in_attr));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering memcpy(&t->saved_out_attr, &out_attr, sizeof(out_attr));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering cfmakeraw(&in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering cfmakeraw(&out_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = tcsetattr(t->in_fd, TCSANOW, &in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = tcsetattr(t->out_fd, TCSANOW, &out_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
7edecf218e5884ec8d1549707b4c7a0572c2d93bThomas Hindoe Paaboel Andersen log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_default(&t->event);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_default() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sigprocmask_many(SIG_BLOCK, SIGINT, SIGQUIT, SIGTERM, SIGWINCH, SIGCHLD, -1);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sigprocmask_many() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGINT, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGQUIT, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGTERM, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGWINCH, terminal_winch_fn, t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering /* force initial redraw on event-loop enter */
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering t->is_dirty = true;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_time(t->event, &t->frame_timer, CLOCK_MONOTONIC, 0, 0, terminal_frame_timer_fn, t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_time() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering }
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = output_new(&t->output, out_fd);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = term_parser_new(&t->parser, true);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = term_screen_new(&t->screen, terminal_write_fn, t, terminal_cmd_fn, t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering if (r < 0)
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering goto error;
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering r = term_screen_set_answerback(t->screen, "systemd-subterm");
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering if (r < 0)
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering goto error;
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering if (r < 0) {
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering goto error;
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering }
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering r = sd_event_add_io(t->event, NULL, in_fd, EPOLLIN, terminal_io_fn, t);
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering if (r < 0)
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering goto error;
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering *out = t;
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering return 0;
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poetteringerror:
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering terminal_free(t);
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering return r;
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering}
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poetteringstatic int terminal_run(Terminal *t) {
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering pid_t pid;
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering assert_return(t, -EINVAL);
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann pid = pty_fork(&t->pty, t->event, terminal_pty_fn, t, t->output->in_width, t->output->in_height);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann if (pid < 0) {
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering log_error("error: cannot fork PTY (%d): %s", pid, strerror(-pid));
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering return pid;
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering } else if (pid == 0) {
c7683ffb53da4ad4334cc9f813e39cffed7e0d0bEvgeny Vereshchagin /* child */
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering char **argv = (char*[]){
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering (char*)getenv("SHELL") ? : (char*)_PATH_BSHELL,
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering NULL
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering };
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering setenv("TERM", "xterm-256color", 1);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering setenv("COLORTERM", "systemd-subterm", 1);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering execve(argv[0], argv, environ);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering log_error("error: cannot exec %s (%d): %m", argv[0], -errno);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering _exit(1);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering }
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering /* parent */
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering return sd_event_loop(t->event);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering}
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering/*
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering * Context Handling
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering */
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poetteringint main(int argc, char *argv[]) {
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering Terminal *t = NULL;
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering int r;
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering r = terminal_new(&t, 0, 1);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering if (r < 0)
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering goto out;
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering r = terminal_run(t);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering if (r < 0)
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poettering goto out;
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poettering
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poetteringout:
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poettering if (r < 0)
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poettering log_error("error: terminal failed (%d): %s", r, strerror(-r));
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering terminal_free(t);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering return -r;
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering}
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering