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