ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.56
Committed: Fri May 1 13:12:17 2015 UTC (9 years, 2 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: rxvt-unicode-rel-9_26, rxvt-unicode-rel-9_25, rxvt-unicode-rel-9_22, rel-1_8
Changes since 1.55: +8 -3 lines
Log Message:
Do not push the streams modules if they are already present.

File Contents

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