]> andersk Git - openssh.git/blob - pty.c
ad9c6d55cda2965b2e9c30a26f8c944f21804c4a
[openssh.git] / pty.c
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$");
18
19 #ifdef HAVE_PTY_H
20 #include <pty.h>
21 #endif /* HAVE_PTY_H */
22
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
40 int 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
198 void 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
208 void 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
258 void 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
This page took 0.047181 seconds and 3 git commands to generate.