ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.35
Committed: Mon May 5 16:51:29 2008 UTC (16 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_3
Changes since 1.34: +2 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.8 // This file is part of libptytty. Do not make local modifications.
2     // http://software.schmorp.de/pkg/libptytty
3    
4     /*----------------------------------------------------------------------*
5 root 1.1 * File: ptytty.C
6     *----------------------------------------------------------------------*
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.2 * Copyright (c) 2004-2006 Marc Lehmann <pcg@goof.com>
11 root 1.12 * Copyright (c) 2006 Emanuele Giaquinta <e.giaquinta@glauco.it>
12 root 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.8 #include "../config.h"
29 root 1.1
30 root 1.3 #include "ptytty.h"
31    
32 root 1.2 #include <cstdlib>
33     #include <cstring>
34 root 1.19 #include <csignal>
35 root 1.2
36     #include <sys/types.h>
37 ayin 1.34 #include <sys/stat.h>
38 root 1.2 #include <unistd.h>
39     #include <fcntl.h>
40    
41 root 1.1 #ifdef HAVE_SYS_IOCTL_H
42     # include <sys/ioctl.h>
43     #endif
44 root 1.2 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
45 root 1.1 # include <sys/stropts.h> /* for I_PUSH */
46     #endif
47 root 1.35 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
48 root 1.1 # include <stropts.h>
49     #endif
50 root 1.2 #if defined(HAVE_PTY_H)
51 root 1.1 # include <pty.h>
52 root 1.2 #elif defined(HAVE_LIBUTIL_H)
53 root 1.1 # include <libutil.h>
54 root 1.2 #elif defined(HAVE_UTIL_H)
55 root 1.1 # include <util.h>
56     #endif
57 root 1.2 #ifdef TTY_GID_SUPPORT
58     #include <grp.h>
59     #endif
60 root 1.1
61     #include <cstdio>
62 root 1.2
63     /////////////////////////////////////////////////////////////////////////////
64 root 1.1
65     /* ------------------------------------------------------------------------- *
66     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
67     * ------------------------------------------------------------------------- */
68     /*
69 ayin 1.26 * Returns pty file descriptor, or -1 on failure
70 root 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 root 1.2 #if defined(UNIX98_PTY)
74 root 1.25
75     static int
76     get_pty (int *fd_tty, char **ttydev)
77     {
78     int pfd;
79 root 1.1
80 root 1.2 # if defined(HAVE_GETPT)
81 root 1.25 pfd = getpt();
82 root 1.2 # elif defined(HAVE_POSIX_OPENPT)
83 root 1.25 pfd = posix_openpt (O_RDWR);
84 root 1.2 # else
85 root 1.25 pfd = open (CLONE_DEVICE, O_RDWR | O_NOCTTY, 0);
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 ayin 1.30 slave = _getpty (&pfd, O_RDWR | O_NONBLOCK | 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 #elif defined(HAVE_DEV_PTC)
143 root 1.1
144 root 1.25 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.1
158 root 1.2 #elif defined(HAVE_DEV_CLONE)
159    
160 root 1.25 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.1
174 root 1.2 #else
175 root 1.1
176 root 1.25 /* 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.24
212 root 1.1 #endif
213    
214     /*----------------------------------------------------------------------*/
215     /*
216 ayin 1.26 * Returns tty file descriptor, or -1 on failure
217 root 1.1 */
218     static int
219     get_tty (char *ttydev)
220     {
221     return open (ttydev, O_RDWR | O_NOCTTY, 0);
222     }
223    
224     /*----------------------------------------------------------------------*/
225     /*
226     * Make our tty a controlling tty so that /dev/tty points to us
227     */
228     static int
229 root 1.2 control_tty (int fd_tty)
230 root 1.1 {
231 ayin 1.28 int fd;
232    
233 root 1.1 setsid ();
234    
235 root 1.2 #if defined(HAVE_DEV_PTMX) && defined(I_PUSH)
236 root 1.1 /*
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     * After we push the STREAMS modules, the first open () on the slave side
243     * (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     * controlling terminal. We must already have close ()d the master side
247     * fd in this child process before we push STREAMS modules on because the
248     * 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     * through - Geoff Wing
252     */
253 root 1.35 #if defined(HAVE_ISASTREAM) && defined(HAVE_STROPTS_H)
254 root 1.1 if (isastream (fd_tty) == 1)
255     # endif
256     {
257     ioctl (fd_tty, I_PUSH, "ptem");
258     ioctl (fd_tty, I_PUSH, "ldterm");
259     ioctl (fd_tty, I_PUSH, "ttcompat");
260     }
261     #endif
262 root 1.2
263 ayin 1.27 #ifdef TIOCSCTTY
264 root 1.2 ioctl (fd_tty, TIOCSCTTY, NULL);
265 ayin 1.27 #else
266 ayin 1.28 fd = open (ttyname (fd_tty), O_RDWR);
267 ayin 1.27 if (fd >= 0)
268     close (fd);
269     #endif
270 root 1.2
271 ayin 1.28 fd = open ("/dev/tty", O_WRONLY);
272 root 1.1 if (fd < 0)
273 root 1.10 return -1; /* fatal */
274 root 1.2
275 root 1.1 close (fd);
276    
277     return 0;
278     }
279    
280 root 1.2 void
281 root 1.4 ptytty::close_tty ()
282 root 1.2 {
283     if (tty < 0)
284     return;
285    
286     close (tty);
287     tty = -1;
288     }
289    
290     bool
291 root 1.4 ptytty::make_controlling_tty ()
292 root 1.2 {
293     return control_tty (tty) >= 0;
294     }
295    
296     void
297 root 1.4 ptytty::set_utf8_mode (bool on)
298 root 1.2 {
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.1 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.32 {
334     /* change group ownership of tty to "tty" */
335 root 1.1 mode = S_IRUSR | S_IWUSR | S_IWGRP;
336     gid = gr->gr_gid;
337     }
338     else
339 ayin 1.31 #endif /* TTY_GID_SUPPORT */
340 root 1.1 {
341     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
342 root 1.2 gid = 0;
343 root 1.1 }
344     }
345     } ttyconf;
346    
347 root 1.4 ptytty_unix::ptytty_unix ()
348 root 1.1 {
349     name = 0;
350 root 1.2 #if UTMP_SUPPORT
351     cmd_pid = 0;
352 root 1.1 #endif
353     }
354    
355 root 1.4 ptytty_unix::~ptytty_unix ()
356 root 1.1 {
357 root 1.2 #if UTMP_SUPPORT
358     logout ();
359     #endif
360 root 1.1 put ();
361     }
362    
363     void
364 root 1.4 ptytty_unix::put ()
365 root 1.2 {
366 root 1.25 if (name)
367     {
368     chmod (name, RESTORE_TTY_MODE);
369     chown (name, 0, ttyconf.gid);
370     }
371 root 1.1
372 root 1.2 close_tty ();
373 root 1.1
374 root 1.2 if (pty >= 0)
375     close (pty);
376 root 1.1
377     free (name);
378    
379     pty = tty = -1;
380     name = 0;
381     }
382    
383     bool
384 root 1.4 ptytty_unix::get ()
385 root 1.1 {
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 root 1.2 chown (name, getuid (), ttyconf.gid); /* fail silently */
397     chmod (name, ttyconf.mode);
398     # ifdef HAVE_REVOKE
399     revoke (name);
400     # endif
401 root 1.1 #endif
402    
403     if ((tty = get_tty (name)) < 0)
404     {
405     put ();
406     return false;
407     }
408     }
409    
410     return true;
411     }
412