File: ttyrescue_mini.c

package info (click to toggle)
termpaint 0.3.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,760 kB
  • sloc: cpp: 40,344; ansic: 10,323; python: 402; sh: 36; makefile: 14
file content (102 lines) | stat: -rw-r--r-- 3,049 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: BSL-1.0

#include <errno.h>
#include <termios.h>
#include <signal.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <stdatomic.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

#ifndef nullptr
#define nullptr ((void*)0)
#endif

static void output(const char *s) {
    (void)!write(2, s, strlen(s)); // ignore error, exiting soon anyway.
}

#define TTYRESCUE_FLAG_ATTACHED    (1 << 0)
#define TTYRESCUE_FLAG_TERMIOS_SET (1 << 1)

struct termpaint_ipcseg {
    atomic_int active;
    atomic_int flags;
    long termios_iflag;
    long termios_oflag;
    long termios_lflag;
    long termios_vintr;
    long termios_vmin;
    long termios_vquit;
    long termios_vstart;
    long termios_vstop;
    long termios_vsusp;
    long termios_vtime;
};

int main(int argc, char** argv) {
    (void) argc; (void) argv;

    struct termpaint_ipcseg *ctlseg = mmap(0, 8048, PROT_READ | PROT_WRITE, MAP_SHARED, 3, 0);
    close(3);
    if (ctlseg == MAP_FAILED) {
        output("ttyrescue: mmap failed. Abort.\n");
        return 1;
    }
    atomic_fetch_or(&ctlseg->flags, TTYRESCUE_FLAG_ATTACHED);

    sigset_t fullset;
    sigfillset(&fullset);
    sigprocmask(SIG_BLOCK, &fullset, NULL);

    struct pollfd fds[1] = { { .fd = 0, .events = POLLIN } };

    while (1) {
        char buf[10];
        ssize_t retval;
        do {
            retval = poll(fds, 1, -1);
        } while (retval == -EINTR);
        if (retval < 0) {
            return 0;
        }
        retval = read(0, buf, 10);
        if (retval == 0) {
            // parent crashed
            int offset = atomic_load(&ctlseg->active);
            if (offset) {
                output((char*)ctlseg + offset);
            }
            if (atomic_load(&ctlseg->flags) & TTYRESCUE_FLAG_TERMIOS_SET) {
                if (tcgetpgrp(2) == getpgrp()) {
                    struct termios tattr;
                    if (tcgetattr(2, &tattr) >= 0) {
                        tattr.c_iflag = (tcflag_t)ctlseg->termios_iflag;
                        tattr.c_oflag = (tcflag_t)ctlseg->termios_oflag;
                        tattr.c_lflag = (tcflag_t)ctlseg->termios_lflag;
                        tattr.c_cc[VINTR] = (cc_t)ctlseg->termios_vintr;
                        tattr.c_cc[VMIN] = (cc_t)ctlseg->termios_vmin;
                        tattr.c_cc[VQUIT] = (cc_t)ctlseg->termios_vquit;
                        tattr.c_cc[VSTART] = (cc_t)ctlseg->termios_vstart;
                        tattr.c_cc[VSTOP] = (cc_t)ctlseg->termios_vstop;
                        tattr.c_cc[VSUSP] = (cc_t)ctlseg->termios_vsusp;
                        tattr.c_cc[VTIME] = (cc_t)ctlseg->termios_vtime;
                        tcsetattr(2, TCSAFLUSH, &tattr);
                    }
                }
            }
            return 0;
        }
        if (retval < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
            continue;
        }
        if (retval > 0) {
            // clean close of parent
            return 0;
        }
    }

    return 0;
}