-
Notifications
You must be signed in to change notification settings - Fork 1
/
pty.c
123 lines (103 loc) · 2.22 KB
/
pty.c
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
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pty.h"
extern int posix_openpt(int); // posix_openpt in libc
extern int grantpt(int); // grantt in libc
extern int unlockpt(int); // unlockpt in libc
extern char *ptsname(int); // ptsname in libc
// 0 => don't use
// -1 => use this pty
int PTYS[3] = {0, 0, 0};
int ptym_open(char *ptyname) {
int psfd = posix_openpt(O_RDWR);
char *pty;
if (psfd < 0)
goto err_ptym;
if (grantpt(psfd) < 0)
goto err_ptym;
if (unlockpt(psfd) < 0)
goto err_ptym;
if ((pty = ptsname(psfd)) == NULL)
goto err_ptym;
strcpy(ptyname, pty);
return psfd;
err_ptym:
perror(ptyname);
return -1;
}
int ptys_open(char *ptyname) {
int fd = open(ptyname, O_RDWR);
if (fd < 0)
goto err_ptys;
return fd;
err_ptys:
perror(ptyname);
return -1;
}
pid_t pty_fork(int ptys[]) {
pid_t pid;
char pty_names[3][20];
for (size_t i = 0; i < 3; i++) {
if (ptys[i] == 0)
continue;
ptys[i] = ptym_open(pty_names[i]);
if (i == STDIN_FILENO) {
set_ter(ptys[STDIN_FILENO], ~ICANON & ~ECHO);
}
if(i == STDERR_FILENO){
set_ter(ptys[STDERR_FILENO], ~ICANON);
}
}
if ((pid = fork()) < 0) {
perror("fork");
return -1;
} else if (pid == 0) { // child
if (setsid() < 0) {
perror("setsid");
return -1;
}
for (size_t i = 0; i < 3; i++) {
if (ptys[i] == 0)
continue;
int tmp_fd = ptys[i];
if ((ptys[i] = ptys_open(pty_names[i])) < 0) {
return -1;
}
close(tmp_fd);
if (dup2(ptys[i], (int)i) != (int)i) {
perror("dup2");
return -1;
}
close(ptys[i]);
}
return 0;
}
// parent
return pid;
}
extern bool FAKE_FD[3]; // in main.c
int pty_fork_exec(char *path, char *arg[]) {
pid_t pid;
for (size_t i = 0; i < 3; i++) {
if (FAKE_FD[i] == true) {
PTYS[i] = -1;
}
}
if ((pid = pty_fork(PTYS)) < 0) {
return -1;
} else if (pid == 0) {
execvp(path, arg);
}
return pid;
}
void set_ter(int fd, tcflag_t flag) {
if (!isatty(fd))
return;
struct termios t;
tcgetattr(fd, &t);
t.c_lflag &= flag;
tcsetattr(fd, TCSANOW, &t);
}