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