ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/ptytty.C
Revision: 1.69
Committed: Mon May 5 16:51:52 2008 UTC (16 years ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: before_dynamic_fontidx, dynamic_fontidx, rel-9_06, rel-9_07, rel-9_05
Changes since 1.68: +8 -6 lines
Log Message:
update_ptytty

File Contents

# User Rev Content
1 root 1.55 // This file is part of libptytty. Do not make local modifications.
2     // http://software.schmorp.de/pkg/libptytty
3    
4     /*----------------------------------------------------------------------*
5 pcg 1.11 * File: ptytty.C
6 pcg 1.1 *----------------------------------------------------------------------*
7     *
8     * All portions of code are copyright by their respective author/s.
9     * Copyright (c) 1999-2001 Geoff Wing <gcw@pobox.com>
10 root 1.30 * Copyright (c) 2004-2006 Marc Lehmann <pcg@goof.com>
11 root 1.58 * Copyright (c) 2006 Emanuele Giaquinta <e.giaquinta@glauco.it>
12 pcg 1.1 *
13     * This program is free software; you can redistribute it and/or modify
14     * it under the terms of the GNU General Public License as published by
15     * the Free Software Foundation; either version 2 of the License, or
16     * (at your option) any later version.
17     *
18     * This program is distributed in the hope that it will be useful,
19     * but WITHOUT ANY WARRANTY; without even the implied warranty of
20     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     * GNU General Public License for more details.
22     *
23     * You should have received a copy of the GNU General Public License
24     * along with this program; if not, write to the Free Software
25     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26     *---------------------------------------------------------------------*/
27    
28 root 1.55 #include "../config.h"
29 root 1.54
30     #include "ptytty.h"
31 pcg 1.1
32 root 1.40 #include <cstdlib>
33     #include <cstring>
34 root 1.59 #include <csignal>
35 root 1.40
36     #include <sys/types.h>
37 root 1.69 #include <sys/stat.h>
38 root 1.40 #include <unistd.h>
39     #include <fcntl.h>
40 root 1.31
41 pcg 1.1 #ifdef HAVE_SYS_IOCTL_H
42     # include <sys/ioctl.h>
43     #endif
44 ayin 1.53 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
45 pcg 1.1 # include <sys/stropts.h> /* for I_PUSH */
46     #endif
47 root 1.69 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
48 pcg 1.10 # include <stropts.h>
49     #endif
50 root 1.31 #if defined(HAVE_PTY_H)
51 root 1.22 # include <pty.h>
52 root 1.31 #elif defined(HAVE_LIBUTIL_H)
53 root 1.16 # include <libutil.h>
54 root 1.31 #elif defined(HAVE_UTIL_H)
55 root 1.17 # include <util.h>
56 pcg 1.1 #endif
57 ayin 1.53 #ifdef TTY_GID_SUPPORT
58     #include <grp.h>
59     #endif
60 pcg 1.1
61 root 1.16 #include <cstdio>
62    
63 root 1.36 /////////////////////////////////////////////////////////////////////////////
64    
65 pcg 1.1 /* ------------------------------------------------------------------------- *
66     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
67     * ------------------------------------------------------------------------- */
68     /*
69 ayin 1.64 * Returns pty file descriptor, or -1 on failure
70 pcg 1.1 * If successful, ttydev is set to the name of the slave device.
71     * fd_tty _may_ also be set to an open fd to the slave device
72     */
73 ayin 1.53 #if defined(UNIX98_PTY)
74 root 1.63
75     static int
76     get_pty (int *fd_tty, char **ttydev)
77     {
78     int pfd;
79 pcg 1.1
80 ayin 1.53 # if defined(HAVE_GETPT)
81 root 1.63 pfd = getpt();
82 ayin 1.53 # elif defined(HAVE_POSIX_OPENPT)
83 root 1.63 pfd = posix_openpt (O_RDWR);
84 ayin 1.44 # else
85 root 1.63 pfd = open (CLONE_DEVICE, O_RDWR | O_NOCTTY, 0);
86 ayin 1.44 # endif
87 root 1.45
88 root 1.63 if (pfd >= 0)
89     {
90     if (grantpt (pfd) == 0 /* change slave permissions */
91     && unlockpt (pfd) == 0)
92 ayin 1.68 {
93     /* slave now unlocked */
94 root 1.63 *ttydev = strdup (ptsname (pfd)); /* get slave's name */
95     return pfd;
96     }
97    
98     close (pfd);
99     }
100    
101     return -1;
102     }
103 root 1.45
104 ayin 1.53 #elif defined(HAVE_OPENPTY)
105 root 1.45
106 root 1.63 static int
107     get_pty (int *fd_tty, char **ttydev)
108     {
109     int pfd;
110     int res;
111 ayin 1.64
112 ayin 1.66 res = openpty (&pfd, fd_tty, NULL, NULL, NULL);
113 root 1.63
114     if (res != -1)
115     {
116 ayin 1.66 *ttydev = strdup (ttyname (*fd_tty));
117 root 1.63 return pfd;
118     }
119    
120     return -1;
121     }
122    
123 ayin 1.53 #elif defined(HAVE__GETPTY)
124 ayin 1.44
125 root 1.63 static int
126     get_pty (int *fd_tty, char **ttydev)
127     {
128     int pfd;
129 ayin 1.66 char *slave;
130 root 1.63
131 ayin 1.66 slave = _getpty (&pfd, O_RDWR | O_NONBLOCK | O_NOCTTY, 0622, 0);
132 root 1.63
133 root 1.69 if (slave != NULL)
134     {
135     *ttydev = strdup (slave);
136     return pfd;
137     }
138 root 1.63
139     return -1;
140     }
141 root 1.45
142 ayin 1.53 #elif defined(HAVE_DEV_PTC)
143 pcg 1.4
144 root 1.63 static int
145     get_pty (int *fd_tty, char **ttydev)
146     {
147     int pfd;
148    
149     if ((pfd = open ("/dev/ptc", O_RDWR | O_NOCTTY, 0)) >= 0)
150     {
151     *ttydev = strdup (ttyname (pfd));
152     return pfd;
153     }
154    
155     return -1;
156     }
157 root 1.45
158 ayin 1.53 #elif defined(HAVE_DEV_CLONE)
159 ayin 1.44
160 root 1.63 static int
161     get_pty (int *fd_tty, char **ttydev)
162     {
163     int pfd;
164    
165     if ((pfd = open ("/dev/ptym/clone", O_RDWR | O_NOCTTY, 0)) >= 0)
166     {
167     *ttydev = strdup (ptsname (pfd));
168     return pfd;
169     }
170    
171     return -1;
172     }
173 root 1.45
174 ayin 1.53 #else
175 root 1.45
176 root 1.63 /* Based on the code in openssh/openbsd-compat/bsd-openpty.c */
177     static int
178     get_pty (int *fd_tty, char **ttydev)
179     {
180     int pfd;
181     int i;
182     char pty_name[32];
183     char tty_name[32];
184     const char *majors = "pqrstuvwxyzabcde";
185     const char *minors = "0123456789abcdef";
186    
187     for (i = 0; i < 256; i++)
188     {
189     snprintf(pty_name, 32, "/dev/pty%c%c", majors[i / 16], minors[i % 16]);
190     snprintf(tty_name, 32, "/dev/tty%c%c", majors[i / 16], minors[i % 16]);
191    
192     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
193     {
194     snprintf(pty_name, 32, "/dev/ptyp%d", i);
195     snprintf(tty_name, 32, "/dev/ttyp%d", i);
196     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
197     continue;
198     }
199    
200     if (access (tty_name, R_OK | W_OK) == 0)
201     {
202     *ttydev = strdup (tty_name);
203     return pfd;
204     }
205    
206     close (pfd);
207     }
208    
209     return -1;
210     }
211 ayin 1.62
212 pcg 1.1 #endif
213 root 1.45
214 pcg 1.1 /*----------------------------------------------------------------------*/
215     /*
216 ayin 1.64 * Returns tty file descriptor, or -1 on failure
217 pcg 1.1 */
218 root 1.16 static int
219     get_tty (char *ttydev)
220 pcg 1.1 {
221 pcg 1.4 return open (ttydev, O_RDWR | O_NOCTTY, 0);
222 pcg 1.1 }
223    
224     /*----------------------------------------------------------------------*/
225     /*
226     * Make our tty a controlling tty so that /dev/tty points to us
227     */
228 root 1.16 static int
229 root 1.36 control_tty (int fd_tty)
230 pcg 1.1 {
231 ayin 1.65 int fd;
232    
233 pcg 1.4 setsid ();
234 root 1.16
235 ayin 1.53 #if defined(HAVE_DEV_PTMX) && defined(I_PUSH)
236 pcg 1.4 /*
237     * Push STREAMS modules:
238     * ptem: pseudo-terminal hardware emulation module.
239     * ldterm: standard terminal line discipline.
240     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
241     *
242 pcg 1.6 * After we push the STREAMS modules, the first open () on the slave side
243 pcg 1.4 * (i.e. the next section between the dashes giving us "tty opened OK")
244     * should make the "ptem" (or "ldterm" depending upon either which OS
245     * version or which set of manual pages you have) module give us a
246 pcg 1.6 * controlling terminal. We must already have close ()d the master side
247 pcg 1.4 * fd in this child process before we push STREAMS modules on because the
248 pcg 1.6 * documentation is really unclear about whether it is any close () on
249     * the master side or the last close () - i.e. a proper STREAMS dismantling
250     * close () - on the master side which causes a hang up to be sent
251 pcg 1.4 * through - Geoff Wing
252     */
253 root 1.69 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
254 pcg 1.4 if (isastream (fd_tty) == 1)
255 root 1.47 # endif
256 pcg 1.1 {
257 pcg 1.4 ioctl (fd_tty, I_PUSH, "ptem");
258     ioctl (fd_tty, I_PUSH, "ldterm");
259     ioctl (fd_tty, I_PUSH, "ttcompat");
260 pcg 1.1 }
261 root 1.47 #endif
262 root 1.45
263 ayin 1.64 #ifdef TIOCSCTTY
264 root 1.45 ioctl (fd_tty, TIOCSCTTY, NULL);
265 ayin 1.64 #else
266 ayin 1.65 fd = open (ttyname (fd_tty), O_RDWR);
267 ayin 1.64 if (fd >= 0)
268     close (fd);
269     #endif
270 root 1.45
271 ayin 1.65 fd = open ("/dev/tty", O_WRONLY);
272 pcg 1.4 if (fd < 0)
273 root 1.56 return -1; /* fatal */
274 root 1.45
275 pcg 1.4 close (fd);
276    
277     return 0;
278 pcg 1.1 }
279 root 1.16
280 root 1.36 void
281 root 1.54 ptytty::close_tty ()
282 root 1.36 {
283     if (tty < 0)
284     return;
285    
286     close (tty);
287     tty = -1;
288     }
289    
290     bool
291 root 1.54 ptytty::make_controlling_tty ()
292 root 1.36 {
293     return control_tty (tty) >= 0;
294     }
295    
296     void
297 root 1.54 ptytty::set_utf8_mode (bool on)
298 root 1.36 {
299     #ifdef IUTF8
300     if (pty < 0)
301     return;
302    
303     struct termios tio;
304    
305     if (tcgetattr (pty, &tio) != -1)
306     {
307     tcflag_t new_cflag = tio.c_iflag;
308    
309     if (on)
310     new_cflag |= IUTF8;
311     else
312     new_cflag &= ~IUTF8;
313    
314     if (new_cflag != tio.c_iflag)
315     {
316     tio.c_iflag = new_cflag;
317     tcsetattr (pty, TCSANOW, &tio);
318     }
319     }
320     #endif
321     }
322    
323 root 1.16 static struct ttyconf {
324     gid_t gid;
325     mode_t mode;
326    
327     ttyconf ()
328     {
329     #ifdef TTY_GID_SUPPORT
330     struct group *gr = getgrnam ("tty");
331    
332     if (gr)
333 ayin 1.68 {
334     /* change group ownership of tty to "tty" */
335 root 1.16 mode = S_IRUSR | S_IWUSR | S_IWGRP;
336     gid = gr->gr_gid;
337     }
338     else
339 ayin 1.67 #endif /* TTY_GID_SUPPORT */
340 root 1.16 {
341     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
342 ayin 1.48 gid = 0;
343 root 1.16 }
344     }
345     } ttyconf;
346    
347 root 1.54 ptytty_unix::ptytty_unix ()
348 root 1.16 {
349     name = 0;
350 root 1.35 #if UTMP_SUPPORT
351     cmd_pid = 0;
352     #endif
353 root 1.16 }
354    
355 root 1.54 ptytty_unix::~ptytty_unix ()
356 root 1.16 {
357 root 1.43 #if UTMP_SUPPORT
358 root 1.35 logout ();
359 root 1.43 #endif
360 root 1.16 put ();
361     }
362    
363     void
364 root 1.54 ptytty_unix::put ()
365 root 1.16 {
366 root 1.63 if (name)
367     {
368     chmod (name, RESTORE_TTY_MODE);
369     chown (name, 0, ttyconf.gid);
370     }
371 root 1.16
372     close_tty ();
373 root 1.50
374     if (pty >= 0)
375     close (pty);
376    
377 root 1.16 free (name);
378    
379     pty = tty = -1;
380     name = 0;
381     }
382    
383     bool
384 root 1.54 ptytty_unix::get ()
385 root 1.16 {
386     /* get master (pty) */
387     if ((pty = get_pty (&tty, &name)) < 0)
388     return false;
389    
390     fcntl (pty, F_SETFL, O_NONBLOCK);
391    
392     /* get slave (tty) */
393     if (tty < 0)
394     {
395     #ifndef NO_SETOWNER_TTYDEV
396 ayin 1.49 chown (name, getuid (), ttyconf.gid); /* fail silently */
397     chmod (name, ttyconf.mode);
398     # ifdef HAVE_REVOKE
399     revoke (name);
400     # endif
401 root 1.16 #endif
402    
403     if ((tty = get_tty (name)) < 0)
404     {
405     put ();
406     return false;
407     }
408     }
409    
410     return true;
411     }
412