-
Notifications
You must be signed in to change notification settings - Fork 5
/
serialsh.m
129 lines (92 loc) · 2.93 KB
/
serialsh.m
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
#include <unistd.h>
#include <termios.h>
#import <sys/event.h>
#import <Foundation/Foundation.h>
int kq = 0;
pid_t pd = 0;
int pipe_shin[2] = { 0 };
int pipe_shout[2] = { 0 };
#define spawn_shin pipe_shin[1]
#define main_sherr pipe_shout[1]
int attribs(int fd, speed_t baudrate)
{
struct termios tty;
memset(&tty, 0x0, sizeof(tty));
if (tcgetattr(fd, &tty) != 0) return -1;
cfsetispeed(&tty, baudrate);
cfsetospeed(&tty, baudrate);
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= (CLOCAL | CREAD);
tty.c_iflag |= (IGNPAR);
tty.c_iflag &= ~(IXON | IXOFF | INLCR | IGNCR);
tty.c_oflag &= ~OPOST;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~PARENB;
tty.c_iflag &= ~INPCK;
tty.c_cflag &= ~CSTOPB;
tty.c_iflag |= INPCK;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 5;
tty.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
if (tcsetattr(fd, TCSANOW, &tty) != 0) return -1;
return 0;
}
void spawnproc(void) {
struct kevent ke;
if (pd == 0) {
if ((pd = fork()) == 0) {
dup2(pipe_shin[0], STDIN_FILENO);
dup2(main_sherr, STDOUT_FILENO);
dup2(main_sherr, STDERR_FILENO);
char *args[] = { "createpty", "-q", "/dev/null", "login", NULL };
execve("/usr/bin/script", args, NULL);
exit(0);
}
EV_SET(&ke, pd, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
kevent(kq, (const struct kevent *)&ke, 1, NULL, 0, NULL);
}
}
int main(void) {
int fd = 0;
char buf[0x400];
struct kevent ke;
if (fork() != 0) return 0;
/* it will works the same if you open /dev/uart.debug-console */
if ((fd = open("/dev/tty.debug-console", O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK)) < 0) return 0;
assert(attribs(fd, B115200) != -1);
dprintf(fd, "\r\n[serialsh]: hello from the userland!\r\n\n");
pipe(pipe_shin);
pipe(pipe_shout);
dup2(pipe_shout[0], STDIN_FILENO);
dup2(spawn_shin, STDOUT_FILENO);
dup2(spawn_shin, STDERR_FILENO);
if ((kq = kqueue()) == -1) {
dprintf(fd, "\r\n[serialsh]: error during initialization!\r\n\n");
close(fd);
return -1;
}
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 5, 0);
kevent(kq, &ke, 1, NULL, 0, NULL);
EV_SET(&ke, 0, EVFILT_READ, EV_ADD, 0, 5, 0);
kevent(kq, &ke, 1, NULL, 0, NULL);
spawnproc();
for (;;) {
memset(&ke, 0x0, sizeof(ke));
if (kevent(kq, NULL, 0, &ke, 1, NULL) == 0) continue;
if (ke.ident == fd) {
ssize_t rd = read(fd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, rd);
} else if (ke.ident) {
if ((ke.filter == EVFILT_PROC) && (ke.ident == pd)) {
waitpid(pd, NULL, 0);
pd = 0;
spawnproc();
}
} else {
ssize_t rd = read(STDIN_FILENO, buf, sizeof(buf));
write(fd, buf, rd);
}
}
return 0;
}