subterm.c revision 5ab887e98d80ffaf05a97abe4cdc1553a85f0637
d657c51f14601d0235434ffb78cf6ac0f27cc83cLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
c9912c5eafa03fdf53e569eaf2e89d7e0932975bDavid Herrmann This file is part of systemd.
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
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 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 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 * 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 * Output Handling
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering log_error("error: cannot read window-size: %m");
47f5a38cdf98a220d6a0d4eb11a710a0a42ae5c4Lennart Poettering if (wsz.ws_col != o->width || wsz.ws_row != o->height) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering len = loop_write(o->fd, o->obuf, o->n_obuf, false);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_write(Output *o, const void *buf, size_t size) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering if (o->n_obuf + size > o->n_obuf && o->n_obuf + size <= sizeof(o->obuf)) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering len = loop_write(o->fd, buf, size, false);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_vnprintf(Output *o, size_t max, const char *format, va_list args) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering assert_return(max <= sizeof(buf), -EINVAL);
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poetteringstatic int output_nprintf(Output *o, size_t max, const char *format, ...) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = output_vnprintf(o, max, format, args);
ec5249a27adb1ffbcd41f2c771e19c3353819456Daniel Mackstatic int output_vprintf(Output *o, const char *format, va_list args) {
5e8d4254f916eb7115ae14de42e7eccf6bc83786Lennart Poettering r = vsnprintf(buf, sizeof(buf), format, args);
10fa421cd2abdc2ae1a07f7c13bfaa4ee6d6de4fDavid Herrmann assert_return(r < (ssize_t)sizeof(buf), -ENOBUFS);
11811e856b0c63439d45edc9c9834ad427e1bb6aDavid Herrmannstatic int output_printf(Output *o, const char *format, ...) {
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmannstatic int output_move_to(Output *o, unsigned int x, unsigned int y) {
931618d08c64083ff7b29c494f482c40a5b05608Daniel Mack /* force the \e[H code as o->cursor_x/y might be out-of-date */
37d54b938faeefd0a5a74f9197a33d78bbb8d6bfDaniel Mack r = output_printf(o, "\e[%u;%uH", y + 1, x + 1);
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);
01608bc86a104423d192364f9534b83d0c75db7fKay Sievers r = output_write(o, line, i * (sizeof(BORDER_HORIZ) - 1));
e57eaef8a187762ca92838c24b9b6460878a800cDavid Herrmannstatic int output_frame_printl(Output *o, const char *format, ...) {
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann /* out of frame? */
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann if (o->cursor_y < 3 || o->cursor_y >= o->height - 3)
e4e66993951e9e349e8008fa7c81184b6e4ae385David Herrmann r = output_vnprintf(o, o->width - 2, format, args);
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann /* disable alternate screen buffer */
0db83ad7334809a6605501e24bad55f3b652c072David Herrmann /* o->fd is owned by the caller */
2d1ca11270e66777c90a449096203afebc37ec9cDavid Herrmann /* enable alternate screen buffer */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering unsigned int i;
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print header-frame */
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_printf(o, BORDER_DOWN_LEFT
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_print_line(o, o->width - 2);
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print body-frame */
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering for (i = 0; i < o->in_height; ++i) {
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print footer-frame */
0aee49d5fba2b2ec94e5c069d937004858a04b4fThomas Hindoe Paaboel Andersen output_printf(o, BORDER_VERT_LEFT
470e72d4081c7d0fd74666b7a45358d5ee2abee1Lennart Poettering /* print header/footer text */
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");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, " Menu: (the following keys are recognized)");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poettering output_frame_printl(o, " ^C: send ^C to the PTY");
b912e251812bb65bed1d545d9748f5b0918f1559Lennart Poetteringstatic void output_draw_screen(Output *o, term_screen *s) {
0f0467e63b0e0688ae9edb1512c1a2637d62ddb4Martin Pitt unsigned int i, j;
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann for (j = 0; j < s->page->height && j < o->in_height; ++j) {
f7a73a2558bceffd983eb7642680e718cd981122David Herrmann for (i = 0; i < s->page->width && i < o->in_width; ++i) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering term_cell *cell = &s->page->lines[j]->cells[i];
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[38;5;%um", cell->attr.fg.c256);
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 case TERM_CCODE_BLACK ... TERM_CCODE_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 90);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.fg.ccode - TERM_CCODE_BLACK + 30);
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 output_printf(o, "\e[48;5;%um", cell->attr.bg.c256);
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 case TERM_CCODE_BLACK ... TERM_CCODE_WHITE:
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[%um", cell->attr.bg.ccode - TERM_CCODE_BLACK + 40);
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 output_printf(o, "\e[%u;%u;%u;%u;%u;%um",
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering str = term_char_resolve(cell->ch, &len, &buf);
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering for (k = 0; k < len; ++k) {
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering output_move_to(o, s->cursor_x + 1, s->cursor_y + 3);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic void output_draw(Output *o, bool menu, term_screen *screen) {
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 * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * +----------------------------------------------------+
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * The body is the part that grows vertically.
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 if (o->in_width < 1 || o->in_height < 1) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[2J" /* erase-in-display: whole screen */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "error: screen too small, need at least 3x7 cells");
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* hide cursor */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* frame-content is contant; only resizes can change it */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_printf(o, "\e[2J" /* erase-in-display: whole screen */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* move cursor to child's position */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* show cursor */
1579dd2c9b8f97e5ec4016d3928d73fea160e55aLennart Poettering if (!(screen->flags & TERM_FLAG_HIDE_CURSOR))
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 if (screen->flags & TERM_FLAG_CURSOR_KEYS)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering if (screen->flags & TERM_FLAG_KEYPAD_MODE)
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering * Terminal Handling
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering /* 16ms timer */
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_now(t->event, CLOCK_MONOTONIC, &usec);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_source_set_time(t->frame_timer, usec);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = sd_event_source_set_enabled(t->frame_timer, SD_EVENT_ONESHOT);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering output_draw(t->output, t->is_menu, t->screen);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic int terminal_frame_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poetteringstatic int terminal_winch_fn(sd_event_source *source, const struct signalfd_siginfo *ssi, void *userdata) {
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = pty_resize(t->pty, t->output->in_width, t->output->in_height);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering log_error("error: pty_resize() (%d): %s", r, strerror(-r));
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
481a0aa2c9803a62cda413b8a1d05571957bb4b5Lennart Poettering log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
39315f9f8dd5a16b4561c5efffc6114c75835011Lennart Poetteringstatic int terminal_push_tmp(Terminal *t, uint32_t ucs4) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_write_tmp(Terminal *t) {
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 log_error("error: cannot write to PTY (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic void terminal_discard_tmp(Terminal *t) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_menu(Terminal *t, const term_seq *seq) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: cannot read from TTY (%d): %m", -errno);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering for (i = 0; i < len; ++i) {
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 log_error("error: term_parser_feed() (%d): %s", type, strerror(-type));
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 } else if (t->is_menu) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering } else if (seq->type == TERM_SEQ_CONTROL && seq->terminator == 0x03) { /* ^C opens the menu */
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = term_screen_feed_text(t->screen, ptr, size);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: term_screen_feed_text() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_write_fn(term_screen *screen, void *userdata, const void *buf, size_t size) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_cmd_fn(term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic Terminal *terminal_free(Terminal *t) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering tcsetattr(t->in_fd, TCSANOW, &t->saved_in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering tcsetattr(t->out_fd, TCSANOW, &t->saved_out_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poetteringstatic int terminal_new(Terminal **out, int in_fd, int out_fd) {
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcgetattr() (%d): %m", -errno);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcgetattr() (%d): %m", -errno);
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 r = tcsetattr(t->in_fd, TCSANOW, &in_attr);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = tcsetattr(t->out_fd, TCSANOW, &out_attr);
7edecf218e5884ec8d1549707b4c7a0572c2d93bThomas Hindoe Paaboel Andersen log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_default() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sigprocmask_many(SIG_BLOCK, SIGINT, SIGQUIT, SIGTERM, SIGWINCH, SIGCHLD, -1);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sigprocmask_many() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGINT, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGQUIT, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGTERM, NULL, NULL);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_signal(t->event, NULL, SIGWINCH, terminal_winch_fn, t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering /* force initial redraw on event-loop enter */
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = sd_event_add_time(t->event, &t->frame_timer, CLOCK_MONOTONIC, 0, 0, terminal_frame_timer_fn, t);
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering log_error("error: sd_event_add_time() (%d): %s", r, strerror(-r));
615aaf412c441e67c7cad2e5ae966b03fca1fae7Lennart Poettering r = term_screen_new(&t->screen, terminal_write_fn, t, terminal_cmd_fn, t);
11ea2781eea4b912d2feb26785ece475e504c57bLennart Poettering r = term_screen_set_answerback(t->screen, "systemd-subterm");
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
d2c643c662e2cb3b6d1445c17c80b4b2998d5c61Lennart Poettering r = sd_event_add_io(t->event, NULL, in_fd, EPOLLIN, terminal_io_fn, t);
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann pid = pty_fork(&t->pty, t->event, terminal_pty_fn, t, t->output->in_width, t->output->in_height);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering log_error("error: cannot fork PTY (%d): %s", pid, strerror(-pid));
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering } else if (pid == 0) {
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering char **argv = (char*[]){
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering (char*)getenv("SHELL") ? : (char*)_PATH_BSHELL,
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering setenv("COLORTERM", "systemd-subterm", 1);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering log_error("error: cannot exec %s (%d): %m", argv[0], -errno);
f9e00a9f5870a9bcae2de8bf1cb3ce04703112e1Lennart Poettering * Context Handling
122676c9d9737f8591429fd5ffc9b454a994741dLennart Poettering log_error("error: terminal failed (%d): %s", r, strerror(-r));