File: ttyrescue_nolibc.c

package info (click to toggle)
termpaint 0.3.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,740 kB
  • sloc: cpp: 40,344; ansic: 10,323; python: 402; sh: 36; makefile: 14
file content (167 lines) | stat: -rw-r--r-- 4,801 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: BSL-1.0
// compile with: gcc -fno-asynchronous-unwind-tables -fno-ident -nostdlib -ffreestanding -static -Os -fvisibility=hidden -std=gnu11 ttyrescue_nolibc.c -o ttyrescue_nolibc
// strip: strip --strip-all --remove-section=.comment --remove-section=.note --remove-section=.eh_frame_hdr --remove-section=.eh_frame --remove-section=.note.gnu.gold-version  ttyrescue_nolibc

#include <poll.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <termios.h>

static int sys_errno;

#define SYS_ERRNO sys_errno

#include "third-party/linux_syscall_support.h"

// hopefully just intrinsics
#include <stdatomic.h>

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

static inline pid_t sysx_tcgetpgrp(int fd) {
    int res;
    if (sys_ioctl(fd,  TIOCGPGRP, &res) < 0) {
        return -1;
    }
    return res;
}

#if defined(__mips__)
#define kernelx_NCCS 23
#elif defined(__sparc__)
#define kernelx_NCCS 17
#else
#define kernelx_NCCS 19
#endif

#if defined(__alpha__) || defined(__powerpc64__) || defined(__powerpc__)
struct kernelx_termios {
        unsigned int c_iflag;
        unsigned int c_oflag;
        unsigned int c_cflag;
        unsigned int c_lflag;
        unsigned char c_cc[kernelx_NCCS];
        unsigned char c_line;
        unsigned int c_ispeed;
        unsigned int c_ospeed;
};
#else
struct kernelx_termios {
        unsigned int c_iflag;
        unsigned int c_oflag;
        unsigned int c_cflag;
        unsigned int c_lflag;
        unsigned char c_line;
        unsigned char c_cc[kernelx_NCCS];
};
#endif


static inline int sysx_tcgetattr(int fd, struct kernelx_termios *attr) {
    return sys_ioctl(fd, TCGETS, attr);
}

static inline pid_t sysx_tcsetattr_flush(int fd, struct kernelx_termios *attr) {
    return sys_ioctl(fd, TCSETSF, attr);
}

int x_strlen(const char *s) {
    int len = 0;
    while (*s) {
        len++;
        s++;
    }
    return len;
}

void *memset(void *s, int c, size_t n) {
    for (size_t i = 0; i < n; i++) {
        ((unsigned char*)s)[i] = c;
    }
    return s;
}

static void output(const char *s) {
    sys_write(2, s, x_strlen(s));
}

#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 _start(int argc, char** argv) {
    (void) argc; (void) argv;

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

    struct kernel_sigset_t fullset;
    sys_sigfillset(&fullset);
    sys_sigprocmask(SIG_BLOCK, &fullset, NULL);

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

    while (1) {
        char buf[10];
        ssize_t retval;
        do {
            retval = sys_poll(fds, 1, -1);
        } while (retval == -EINTR);
        if (retval < 0) {
            sys_exit_group(0);
        }
        retval = sys_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 (sysx_tcgetpgrp(2) == sys_getpgrp()) {
                    struct kernelx_termios tattr;
                    sysx_tcgetattr(2, &tattr);
                    tattr.c_iflag = (unsigned int)ctlseg->termios_iflag;
                    tattr.c_oflag = (unsigned int)ctlseg->termios_oflag;
                    tattr.c_lflag = (unsigned int)ctlseg->termios_lflag;
                    tattr.c_cc[VINTR] = (unsigned char)ctlseg->termios_vintr;
                    tattr.c_cc[VMIN] = (unsigned char)ctlseg->termios_vmin;
                    tattr.c_cc[VQUIT] = (unsigned char)ctlseg->termios_vquit;
                    tattr.c_cc[VSTART] = (unsigned char)ctlseg->termios_vstart;
                    tattr.c_cc[VSTOP] = (unsigned char)ctlseg->termios_vstop;
                    tattr.c_cc[VSUSP] = (unsigned char)ctlseg->termios_vsusp;
                    tattr.c_cc[VTIME] = (unsigned char)ctlseg->termios_vtime;
                    sysx_tcsetattr_flush(2, &tattr);
                }
            }
            sys_exit_group(0);
        }
        if (retval > 0) {
            // clean close of parent
            sys_exit_group(0);
        }
    }

    sys_exit_group(0);
}