ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.29
Committed: Thu Jun 28 17:41:01 2007 UTC (17 years ago) by ayin
Content type: text/plain
Branch: MAIN
Changes since 1.28: +2 -3 lines
Log Message:
When using openpty, get the slave name with ttyname rather than with
the openpty broken interface.

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     #include <unistd.h>
38     #include <fcntl.h>
39    
40 root 1.1 #ifdef HAVE_SYS_IOCTL_H
41     # include <sys/ioctl.h>
42     #endif
43 root 1.2 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
44 root 1.1 # include <sys/stropts.h> /* for I_PUSH */
45     #endif
46     #ifdef HAVE_ISASTREAM
47     # include <stropts.h>
48     #endif
49 root 1.2 #if defined(HAVE_PTY_H)
50 root 1.1 # include <pty.h>
51 root 1.2 #elif defined(HAVE_LIBUTIL_H)
52 root 1.1 # include <libutil.h>
53 root 1.2 #elif defined(HAVE_UTIL_H)
54 root 1.1 # include <util.h>
55     #endif
56 root 1.2 #ifdef TTY_GID_SUPPORT
57     #include <grp.h>
58     #endif
59 root 1.1
60     #include <cstdio>
61 root 1.2
62     /////////////////////////////////////////////////////////////////////////////
63 root 1.1
64     /* ------------------------------------------------------------------------- *
65     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
66     * ------------------------------------------------------------------------- */
67     /*
68 ayin 1.26 * Returns pty file descriptor, or -1 on failure
69 root 1.1 * If successful, ttydev is set to the name of the slave device.
70     * fd_tty _may_ also be set to an open fd to the slave device
71     */
72 root 1.2 #if defined(UNIX98_PTY)
73 root 1.25
74     static int
75     get_pty (int *fd_tty, char **ttydev)
76     {
77     int pfd;
78 root 1.1
79 root 1.2 # if defined(HAVE_GETPT)
80 root 1.25 pfd = getpt();
81 root 1.2 # elif defined(HAVE_POSIX_OPENPT)
82 root 1.25 pfd = posix_openpt (O_RDWR);
83 root 1.2 # else
84 root 1.25 pfd = open (CLONE_DEVICE, O_RDWR | O_NOCTTY, 0);
85 root 1.2 # endif
86 root 1.1
87 root 1.25 if (pfd >= 0)
88     {
89     if (grantpt (pfd) == 0 /* change slave permissions */
90     && unlockpt (pfd) == 0)
91     { /* slave now unlocked */
92     *ttydev = strdup (ptsname (pfd)); /* get slave's name */
93     return pfd;
94     }
95    
96     close (pfd);
97     }
98    
99     return -1;
100     }
101 root 1.2
102     #elif defined(HAVE_OPENPTY)
103 root 1.1
104 root 1.25 static int
105     get_pty (int *fd_tty, char **ttydev)
106     {
107     int pfd;
108     int res;
109 ayin 1.26
110 ayin 1.29 res = openpty (&pfd, fd_tty, NULL, NULL, NULL);
111 root 1.25
112     if (res != -1)
113     {
114 ayin 1.29 *ttydev = strdup (ttyname (*fd_tty));
115 root 1.25 return pfd;
116     }
117    
118     return -1;
119     }
120    
121 root 1.2 #elif defined(HAVE__GETPTY)
122    
123 root 1.25 static int
124     get_pty (int *fd_tty, char **ttydev)
125     {
126     int pfd;
127    
128     *ttydev = _getpty (&pfd, O_RDWR | O_NONBLOCK | O_NOCTTY, 0622, 0);
129    
130     if (*ttydev != NULL)
131     return pfd;
132    
133     return -1;
134     }
135 root 1.1
136 root 1.2 #elif defined(HAVE_DEV_PTC)
137 root 1.1
138 root 1.25 static int
139     get_pty (int *fd_tty, char **ttydev)
140     {
141     int pfd;
142    
143     if ((pfd = open ("/dev/ptc", O_RDWR | O_NOCTTY, 0)) >= 0)
144     {
145     *ttydev = strdup (ttyname (pfd));
146     return pfd;
147     }
148    
149     return -1;
150     }
151 root 1.1
152 root 1.2 #elif defined(HAVE_DEV_CLONE)
153    
154 root 1.25 static int
155     get_pty (int *fd_tty, char **ttydev)
156     {
157     int pfd;
158    
159     if ((pfd = open ("/dev/ptym/clone", O_RDWR | O_NOCTTY, 0)) >= 0)
160     {
161     *ttydev = strdup (ptsname (pfd));
162     return pfd;
163     }
164    
165     return -1;
166     }
167 root 1.1
168 root 1.2 #else
169 root 1.1
170 root 1.25 /* Based on the code in openssh/openbsd-compat/bsd-openpty.c */
171     static int
172     get_pty (int *fd_tty, char **ttydev)
173     {
174     int pfd;
175     int i;
176     char pty_name[32];
177     char tty_name[32];
178     const char *majors = "pqrstuvwxyzabcde";
179     const char *minors = "0123456789abcdef";
180    
181     for (i = 0; i < 256; i++)
182     {
183     snprintf(pty_name, 32, "/dev/pty%c%c", majors[i / 16], minors[i % 16]);
184     snprintf(tty_name, 32, "/dev/tty%c%c", majors[i / 16], minors[i % 16]);
185    
186     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
187     {
188     snprintf(pty_name, 32, "/dev/ptyp%d", i);
189     snprintf(tty_name, 32, "/dev/ttyp%d", i);
190     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) == -1)
191     continue;
192     }
193    
194     if (access (tty_name, R_OK | W_OK) == 0)
195     {
196     *ttydev = strdup (tty_name);
197     return pfd;
198     }
199    
200     close (pfd);
201     }
202    
203     return -1;
204     }
205 ayin 1.24
206 root 1.1 #endif
207    
208     /*----------------------------------------------------------------------*/
209     /*
210 ayin 1.26 * Returns tty file descriptor, or -1 on failure
211 root 1.1 */
212     static int
213     get_tty (char *ttydev)
214     {
215     return open (ttydev, O_RDWR | O_NOCTTY, 0);
216     }
217    
218     /*----------------------------------------------------------------------*/
219     /*
220     * Make our tty a controlling tty so that /dev/tty points to us
221     */
222     static int
223 root 1.2 control_tty (int fd_tty)
224 root 1.1 {
225 ayin 1.28 int fd;
226    
227 root 1.1 setsid ();
228    
229 root 1.2 #if defined(HAVE_DEV_PTMX) && defined(I_PUSH)
230 root 1.1 /*
231     * Push STREAMS modules:
232     * ptem: pseudo-terminal hardware emulation module.
233     * ldterm: standard terminal line discipline.
234     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
235     *
236     * After we push the STREAMS modules, the first open () on the slave side
237     * (i.e. the next section between the dashes giving us "tty opened OK")
238     * should make the "ptem" (or "ldterm" depending upon either which OS
239     * version or which set of manual pages you have) module give us a
240     * controlling terminal. We must already have close ()d the master side
241     * fd in this child process before we push STREAMS modules on because the
242     * documentation is really unclear about whether it is any close () on
243     * the master side or the last close () - i.e. a proper STREAMS dismantling
244     * close () - on the master side which causes a hang up to be sent
245     * through - Geoff Wing
246     */
247     # ifdef HAVE_ISASTREAM
248     if (isastream (fd_tty) == 1)
249     # endif
250     {
251     ioctl (fd_tty, I_PUSH, "ptem");
252     ioctl (fd_tty, I_PUSH, "ldterm");
253     ioctl (fd_tty, I_PUSH, "ttcompat");
254     }
255     #endif
256 root 1.2
257 ayin 1.27 #ifdef TIOCSCTTY
258 root 1.2 ioctl (fd_tty, TIOCSCTTY, NULL);
259 ayin 1.27 #else
260 ayin 1.28 fd = open (ttyname (fd_tty), O_RDWR);
261 ayin 1.27 if (fd >= 0)
262     close (fd);
263     #endif
264 root 1.2
265 ayin 1.28 fd = open ("/dev/tty", O_WRONLY);
266 root 1.1 if (fd < 0)
267 root 1.10 return -1; /* fatal */
268 root 1.2
269 root 1.1 close (fd);
270    
271     return 0;
272     }
273    
274 root 1.2 void
275 root 1.4 ptytty::close_tty ()
276 root 1.2 {
277     if (tty < 0)
278     return;
279    
280     close (tty);
281     tty = -1;
282     }
283    
284     bool
285 root 1.4 ptytty::make_controlling_tty ()
286 root 1.2 {
287     return control_tty (tty) >= 0;
288     }
289    
290     void
291 root 1.4 ptytty::set_utf8_mode (bool on)
292 root 1.2 {
293     #ifdef IUTF8
294     if (pty < 0)
295     return;
296    
297     struct termios tio;
298    
299     if (tcgetattr (pty, &tio) != -1)
300     {
301     tcflag_t new_cflag = tio.c_iflag;
302    
303     if (on)
304     new_cflag |= IUTF8;
305     else
306     new_cflag &= ~IUTF8;
307    
308     if (new_cflag != tio.c_iflag)
309     {
310     tio.c_iflag = new_cflag;
311     tcsetattr (pty, TCSANOW, &tio);
312     }
313     }
314     #endif
315     }
316    
317 root 1.1 static struct ttyconf {
318     gid_t gid;
319     mode_t mode;
320    
321     ttyconf ()
322     {
323     #ifdef TTY_GID_SUPPORT
324     struct group *gr = getgrnam ("tty");
325    
326     if (gr)
327     { /* change group ownership of tty to "tty" */
328     mode = S_IRUSR | S_IWUSR | S_IWGRP;
329     gid = gr->gr_gid;
330     }
331     else
332     #endif /* TTY_GID_SUPPORT */
333     {
334     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
335 root 1.2 gid = 0;
336 root 1.1 }
337     }
338     } ttyconf;
339    
340 root 1.4 ptytty_unix::ptytty_unix ()
341 root 1.1 {
342     name = 0;
343 root 1.2 #if UTMP_SUPPORT
344     cmd_pid = 0;
345 root 1.1 #endif
346     }
347    
348 root 1.4 ptytty_unix::~ptytty_unix ()
349 root 1.1 {
350 root 1.2 #if UTMP_SUPPORT
351     logout ();
352     #endif
353 root 1.1 put ();
354     }
355    
356     void
357 root 1.4 ptytty_unix::put ()
358 root 1.2 {
359 root 1.25 if (name)
360     {
361     chmod (name, RESTORE_TTY_MODE);
362     chown (name, 0, ttyconf.gid);
363     }
364 root 1.1
365 root 1.2 close_tty ();
366 root 1.1
367 root 1.2 if (pty >= 0)
368     close (pty);
369 root 1.1
370     free (name);
371    
372     pty = tty = -1;
373     name = 0;
374     }
375    
376     bool
377 root 1.4 ptytty_unix::get ()
378 root 1.1 {
379     /* get master (pty) */
380     if ((pty = get_pty (&tty, &name)) < 0)
381     return false;
382    
383     fcntl (pty, F_SETFL, O_NONBLOCK);
384    
385     /* get slave (tty) */
386     if (tty < 0)
387     {
388     #ifndef NO_SETOWNER_TTYDEV
389 root 1.2 chown (name, getuid (), ttyconf.gid); /* fail silently */
390     chmod (name, ttyconf.mode);
391     # ifdef HAVE_REVOKE
392     revoke (name);
393     # endif
394 root 1.1 #endif
395    
396     if ((tty = get_tty (name)) < 0)
397     {
398     put ();
399     return false;
400     }
401     }
402    
403     return true;
404     }
405