-
Notifications
You must be signed in to change notification settings - Fork 79
/
Copy pathchannel_forkpty.c
186 lines (158 loc) · 3.98 KB
/
channel_forkpty.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
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*
20150212
20241209 - reformated using clang-format
Jan Mojzis
Public domain.
*/
#include <unistd.h>
#if defined(sun) || defined(__hpux)
#include <sys/stropts.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
extern char *ptsname(int);
extern int grantpt(int);
extern int unlockpt(int);
#include "hasopenpty.h"
#ifdef HASOPENPTY
extern int openpty(int *, int *, char *, struct termios *, struct winsize *);
#endif
#include "haslogintty.h"
#ifdef HASLOGINTTY
extern int login_tty(int);
#endif
#include "e.h"
#include "coe.h"
#include "blocking.h"
#include "global.h"
#include "channel.h"
#ifndef HASLOGINTTY
static int login_tty_(int fd) {
char *name;
setsid();
#ifdef TIOCSCTTY
if (ioctl(fd, TIOCSCTTY, (char *) 0) == -1) return -1;
#endif
name = ttyname(fd);
if (!name) return -1;
#ifndef TIOCSCTTY
if (fd != 0) close(0);
if (fd != 1) close(1);
if (fd != 2) close(2);
close(open(name, O_RDWR));
#endif
if (dup2(fd, 0) == -1) return -1;
if (dup2(fd, 1) == -1) return -1;
if (dup2(fd, 2) == -1) return -1;
if (fd > 2) close(fd);
return 0;
}
#endif
#ifndef HASOPENPTY
static int openpty_(int *amaster, int *aslave) {
int master = -1, slave = -1;
char *slave_name;
static const char *fn[] = {"/dev/ptmx", "/dev/ptc", 0};
long long i;
for (i = 0; fn[i]; ++i) {
master = open(fn[i], O_RDWR | O_NOCTTY);
if (master != -1) break;
}
if (master == -1) return -1;
if (grantpt(master) == -1) {
close(master);
return -1;
}
if (unlockpt(master) == -1) {
close(master);
return -1;
}
slave_name = ptsname(master);
if (!slave_name) {
close(master);
return -1;
}
slave = open(slave_name, O_RDWR | O_NOCTTY);
if (slave == -1) {
close(master);
return -1;
}
#if defined(sun) || defined(__hpux)
ioctl(slave, I_PUSH, "ptem");
ioctl(slave, I_PUSH, "ldterm");
#endif
#if defined(sun)
ioctl(slave, I_PUSH, "ttcompat");
#endif
if (amaster) *amaster = master;
if (aslave) *aslave = slave;
return 0;
}
#endif
int channel_openpty(int *amaster, int *aslave) {
#ifdef HASOPENPTY
if (openpty(amaster, aslave, 0, 0, 0) == -1) return 0;
#else
if (openpty_(amaster, aslave) == -1) return 0;
#endif
if (!ttyname(*aslave)) {
close(*amaster);
close(*aslave);
return 0;
}
return 1;
}
/*
The 'channel_forkpty' function is used to create a new process
operating in a pseudoterminal. Function sets 3 integers in 'fd[3]':
fd[0] and fd[1] is pseudoterminal fd
fd[2] is always -1
*/
long long channel_forkpty(int fd[3], int master, int slave) {
long long pid, r;
char ch;
int pi[2];
if (!ttyname(slave)) return -1;
if (pipe(pi) == -1) return -1;
fd[0] = fd[1] = master;
fd[2] = -1;
pid = fork();
switch (pid) {
case -1:
close(pi[0]);
close(pi[1]);
close(slave);
close(master);
return -1;
case 0:
close(master);
close(pi[0]);
#ifdef HASLOGINTTY
if (login_tty(slave) == -1) global_die(111);
#else
if (login_tty_(slave) == -1) global_die(111);
#endif
/* Trigger a read event on the other side of the pipe. */
do { r = write(pi[1], "", 1); } while (r == -1 && errno == EINTR);
close(pi[1]);
return 0;
default:
close(pi[1]);
coe_enable(master);
blocking_disable(master);
/*
Wait until child calls login_tty(slave), so that we can safely
close(slave). Fixes race condition between close(slave) in parent
and login_tty(slave) in child process.
*/
do {
r = read(pi[0], &ch, sizeof ch);
} while (r == -1 && errno == EINTR);
close(pi[0]);
close(slave);
return pid;
}
}