summaryrefslogtreecommitdiff
path: root/pty.c
diff options
context:
space:
mode:
Diffstat (limited to 'pty.c')
-rw-r--r--pty.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/pty.c b/pty.c
new file mode 100644
index 000000000..440994b51
--- /dev/null
+++ b/pty.c
@@ -0,0 +1,264 @@
1/*
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"
17RCSID("$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
36int 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
194void 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
204void 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
254void 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