diff options
Diffstat (limited to 'pty.c')
-rw-r--r-- | pty.c | 264 |
1 files changed, 264 insertions, 0 deletions
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | |||
3 | pty.c | ||
4 | |||
5 | Author: Tatu Ylonen <ylo@cs.hut.fi> | ||
6 | |||
7 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
8 | All rights reserved | ||
9 | |||
10 | Created: Fri Mar 17 04:37:25 1995 ylo | ||
11 | |||
12 | Allocating a pseudo-terminal, and making it the controlling tty. | ||
13 | |||
14 | */ | ||
15 | |||
16 | #include "includes.h" | ||
17 | RCSID("$Id: pty.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); | ||
18 | |||
19 | #include "pty.h" | ||
20 | #include "ssh.h" | ||
21 | |||
22 | /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */ | ||
23 | #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY) | ||
24 | #undef HAVE_DEV_PTMX | ||
25 | #endif | ||
26 | |||
27 | #ifndef O_NOCTTY | ||
28 | #define O_NOCTTY 0 | ||
29 | #endif | ||
30 | |||
31 | /* Allocates and opens a pty. Returns 0 if no pty could be allocated, | ||
32 | or nonzero if a pty was successfully allocated. On success, open file | ||
33 | descriptors for the pty and tty sides and the name of the tty side are | ||
34 | returned (the buffer must be able to hold at least 64 characters). */ | ||
35 | |||
36 | int pty_allocate(int *ptyfd, int *ttyfd, char *namebuf) | ||
37 | { | ||
38 | #ifdef HAVE_OPENPTY | ||
39 | |||
40 | /* openpty(3) exists in OSF/1 and some other os'es */ | ||
41 | |||
42 | int i; | ||
43 | |||
44 | i = openpty(ptyfd, ttyfd, namebuf, NULL, NULL); | ||
45 | |||
46 | if (i < 0) | ||
47 | { | ||
48 | error("openpty: %.100s", strerror(errno)); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | return 1; | ||
53 | |||
54 | #else /* HAVE_OPENPTY */ | ||
55 | #ifdef HAVE__GETPTY | ||
56 | |||
57 | /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more | ||
58 | pty's automagically when needed */ | ||
59 | |||
60 | char *slave; | ||
61 | |||
62 | slave = _getpty(ptyfd, O_RDWR, 0622, 0); | ||
63 | if (slave == NULL) | ||
64 | { | ||
65 | error("_getpty: %.100s", strerror(errno)); | ||
66 | return 0; | ||
67 | } | ||
68 | strcpy(namebuf, slave); | ||
69 | /* Open the slave side. */ | ||
70 | *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); | ||
71 | if (*ttyfd < 0) | ||
72 | { | ||
73 | error("%.200s: %.100s", namebuf, strerror(errno)); | ||
74 | close(*ptyfd); | ||
75 | return 0; | ||
76 | } | ||
77 | return 1; | ||
78 | |||
79 | #else /* HAVE__GETPTY */ | ||
80 | #ifdef HAVE_DEV_PTMX | ||
81 | /* This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 also has | ||
82 | bsd-style ptys, but they simply do not work.) */ | ||
83 | |||
84 | int ptm; | ||
85 | char *pts; | ||
86 | |||
87 | ptm = open("/dev/ptmx", O_RDWR|O_NOCTTY); | ||
88 | if (ptm < 0) | ||
89 | { | ||
90 | error("/dev/ptmx: %.100s", strerror(errno)); | ||
91 | return 0; | ||
92 | } | ||
93 | if (grantpt(ptm) < 0) | ||
94 | { | ||
95 | error("grantpt: %.100s", strerror(errno)); | ||
96 | return 0; | ||
97 | } | ||
98 | if (unlockpt(ptm) < 0) | ||
99 | { | ||
100 | error("unlockpt: %.100s", strerror(errno)); | ||
101 | return 0; | ||
102 | } | ||
103 | pts = ptsname(ptm); | ||
104 | if (pts == NULL) | ||
105 | error("Slave pty side name could not be obtained."); | ||
106 | strcpy(namebuf, pts); | ||
107 | *ptyfd = ptm; | ||
108 | |||
109 | /* Open the slave side. */ | ||
110 | *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); | ||
111 | if (*ttyfd < 0) | ||
112 | { | ||
113 | error("%.100s: %.100s", namebuf, strerror(errno)); | ||
114 | close(*ptyfd); | ||
115 | return 0; | ||
116 | } | ||
117 | /* Push the appropriate streams modules, as described in Solaris pts(7). */ | ||
118 | if (ioctl(*ttyfd, I_PUSH, "ptem") < 0) | ||
119 | error("ioctl I_PUSH ptem: %.100s", strerror(errno)); | ||
120 | if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0) | ||
121 | error("ioctl I_PUSH ldterm: %.100s", strerror(errno)); | ||
122 | if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0) | ||
123 | error("ioctl I_PUSH ttcompat: %.100s", strerror(errno)); | ||
124 | return 1; | ||
125 | |||
126 | #else /* HAVE_DEV_PTMX */ | ||
127 | #ifdef HAVE_DEV_PTS_AND_PTC | ||
128 | |||
129 | /* AIX-style pty code. */ | ||
130 | |||
131 | const char *name; | ||
132 | |||
133 | *ptyfd = open("/dev/ptc", O_RDWR|O_NOCTTY); | ||
134 | if (*ptyfd < 0) | ||
135 | { | ||
136 | error("Could not open /dev/ptc: %.100s", strerror(errno)); | ||
137 | return 0; | ||
138 | } | ||
139 | name = ttyname(*ptyfd); | ||
140 | if (!name) | ||
141 | fatal("Open of /dev/ptc returns device for which ttyname fails."); | ||
142 | strcpy(namebuf, name); | ||
143 | *ttyfd = open(name, O_RDWR|O_NOCTTY); | ||
144 | if (*ttyfd < 0) | ||
145 | { | ||
146 | error("Could not open pty slave side %.100s: %.100s", | ||
147 | name, strerror(errno)); | ||
148 | close(*ptyfd); | ||
149 | return 0; | ||
150 | } | ||
151 | return 1; | ||
152 | |||
153 | #else /* HAVE_DEV_PTS_AND_PTC */ | ||
154 | /* BSD-style pty code. */ | ||
155 | |||
156 | char buf[64]; | ||
157 | int i; | ||
158 | const char *ptymajors = | ||
159 | "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
160 | const char *ptyminors = "0123456789abcdef"; | ||
161 | int num_minors = strlen(ptyminors); | ||
162 | int num_ptys = strlen(ptymajors) * num_minors; | ||
163 | |||
164 | for (i = 0; i < num_ptys; i++) | ||
165 | { | ||
166 | snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors], | ||
167 | ptyminors[i % num_minors]); | ||
168 | *ptyfd = open(buf, O_RDWR|O_NOCTTY); | ||
169 | if (*ptyfd < 0) | ||
170 | continue; | ||
171 | snprintf(namebuf, sizeof buf, "/dev/tty%c%c", ptymajors[i / num_minors], | ||
172 | ptyminors[i % num_minors]); | ||
173 | |||
174 | /* Open the slave side. */ | ||
175 | *ttyfd = open(namebuf, O_RDWR|O_NOCTTY); | ||
176 | if (*ttyfd < 0) | ||
177 | { | ||
178 | error("%.100s: %.100s", namebuf, strerror(errno)); | ||
179 | close(*ptyfd); | ||
180 | return 0; | ||
181 | } | ||
182 | return 1; | ||
183 | } | ||
184 | return 0; | ||
185 | #endif /* HAVE_DEV_PTS_AND_PTC */ | ||
186 | #endif /* HAVE_DEV_PTMX */ | ||
187 | #endif /* HAVE__GETPTY */ | ||
188 | #endif /* HAVE_OPENPTY */ | ||
189 | } | ||
190 | |||
191 | /* Releases the tty. Its ownership is returned to root, and permissions to | ||
192 | 0666. */ | ||
193 | |||
194 | void pty_release(const char *ttyname) | ||
195 | { | ||
196 | if (chown(ttyname, (uid_t)0, (gid_t)0) < 0) | ||
197 | debug("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno)); | ||
198 | if (chmod(ttyname, (mode_t)0666) < 0) | ||
199 | debug("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno)); | ||
200 | } | ||
201 | |||
202 | /* Makes the tty the processes controlling tty and sets it to sane modes. */ | ||
203 | |||
204 | void pty_make_controlling_tty(int *ttyfd, const char *ttyname) | ||
205 | { | ||
206 | int fd; | ||
207 | |||
208 | /* First disconnect from the old controlling tty. */ | ||
209 | #ifdef TIOCNOTTY | ||
210 | fd = open("/dev/tty", O_RDWR|O_NOCTTY); | ||
211 | if (fd >= 0) | ||
212 | { | ||
213 | (void)ioctl(fd, TIOCNOTTY, NULL); | ||
214 | close(fd); | ||
215 | } | ||
216 | #endif /* TIOCNOTTY */ | ||
217 | if (setsid() < 0) | ||
218 | error("setsid: %.100s", strerror(errno)); | ||
219 | |||
220 | /* Verify that we are successfully disconnected from the controlling tty. */ | ||
221 | fd = open("/dev/tty", O_RDWR|O_NOCTTY); | ||
222 | if (fd >= 0) | ||
223 | { | ||
224 | error("Failed to disconnect from controlling tty."); | ||
225 | close(fd); | ||
226 | } | ||
227 | |||
228 | /* Make it our controlling tty. */ | ||
229 | #ifdef TIOCSCTTY | ||
230 | debug("Setting controlling tty using TIOCSCTTY."); | ||
231 | /* We ignore errors from this, because HPSUX defines TIOCSCTTY, but returns | ||
232 | EINVAL with these arguments, and there is absolutely no documentation. */ | ||
233 | ioctl(*ttyfd, TIOCSCTTY, NULL); | ||
234 | #endif /* TIOCSCTTY */ | ||
235 | fd = open(ttyname, O_RDWR); | ||
236 | if (fd < 0) | ||
237 | error("%.100s: %.100s", ttyname, strerror(errno)); | ||
238 | else | ||
239 | close(fd); | ||
240 | |||
241 | /* Verify that we now have a controlling tty. */ | ||
242 | fd = open("/dev/tty", O_WRONLY); | ||
243 | if (fd < 0) | ||
244 | error("open /dev/tty failed - could not set controlling tty: %.100s", | ||
245 | strerror(errno)); | ||
246 | else | ||
247 | { | ||
248 | close(fd); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | /* Changes the window size associated with the pty. */ | ||
253 | |||
254 | void pty_change_window_size(int ptyfd, int row, int col, | ||
255 | int xpixel, int ypixel) | ||
256 | { | ||
257 | struct winsize w; | ||
258 | w.ws_row = row; | ||
259 | w.ws_col = col; | ||
260 | w.ws_xpixel = xpixel; | ||
261 | w.ws_ypixel = ypixel; | ||
262 | (void)ioctl(ptyfd, TIOCSWINSZ, &w); | ||
263 | } | ||
264 | |||