ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.46
Committed: Tue Dec 20 21:03:21 2011 UTC (12 years, 6 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.45: +1 -3 lines
Log Message:
Includes cleanup.

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