ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/ptytty.C
Revision: 1.33
Committed: Wed Jan 11 23:08:54 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-7_0
Changes since 1.32: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*--------------------------------*-C-*---------------------------------*
2 pcg 1.11 * File: ptytty.C
3 pcg 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1999-2001 Geoff Wing <gcw@pobox.com>
7 root 1.30 * Copyright (c) 2004-2006 Marc Lehmann <pcg@goof.com>
8 pcg 1.1 *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License as published by
11     * the Free Software Foundation; either version 2 of the License, or
12     * (at your option) any later version.
13     *
14     * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18     *
19     * You should have received a copy of the GNU General Public License
20     * along with this program; if not, write to the Free Software
21     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22     *---------------------------------------------------------------------*/
23    
24     #include "../config.h" /* NECESSARY */
25 root 1.16 #include "rxvt.h"
26 pcg 1.1
27 pcg 1.8 # include <cstdlib>
28 root 1.31 # include <cstring>
29    
30 pcg 1.1 #ifdef HAVE_SYS_TYPES_H
31     # include <sys/types.h>
32     #endif
33     #ifdef HAVE_UNISTD_H
34     # include <unistd.h>
35     #endif
36     #ifdef HAVE_FCNTL_H
37     # include <fcntl.h>
38     #endif
39     #ifdef HAVE_SYS_IOCTL_H
40     # include <sys/ioctl.h>
41     #endif
42 root 1.12 #if defined(PTYS_ARE_PTMX) && defined(HAVE_SYS_STROPTS_H)
43 pcg 1.1 # include <sys/stropts.h> /* for I_PUSH */
44     #endif
45 pcg 1.10 #ifdef HAVE_ISASTREAM
46     # include <stropts.h>
47     #endif
48 root 1.31 #if defined(HAVE_PTY_H)
49 root 1.22 # include <pty.h>
50 root 1.31 #elif defined(HAVE_LIBUTIL_H)
51 root 1.16 # include <libutil.h>
52 root 1.31 #elif defined(HAVE_UTIL_H)
53 root 1.17 # include <util.h>
54 pcg 1.1 #endif
55    
56 root 1.16 #include <cstdio>
57     #include <grp.h>
58    
59 pcg 1.1 /* ------------------------------------------------------------------------- *
60     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
61     * ------------------------------------------------------------------------- */
62     /*
63     * Returns pty file descriptor, or -1 on failure
64     * If successful, ttydev is set to the name of the slave device.
65     * fd_tty _may_ also be set to an open fd to the slave device
66     */
67 root 1.16 static int
68     get_pty (int *fd_tty, char **ttydev)
69 pcg 1.1 {
70 pcg 1.4 int pfd;
71 pcg 1.1
72     #ifdef PTYS_ARE_OPENPTY
73 root 1.26 char tty_name[sizeof "/dev/pts/????\0"];
74 pcg 1.4
75 root 1.27 rxvt_privileges(RESTORE);
76     int res = openpty (&pfd, fd_tty, tty_name, NULL, NULL);
77     rxvt_privileges(IGNORE);
78    
79     if (res != -1)
80 pcg 1.4 {
81 pcg 1.6 *ttydev = strdup (tty_name);
82 pcg 1.4 return pfd;
83 pcg 1.1 }
84     #endif
85    
86     #ifdef PTYS_ARE__GETPTY
87 pcg 1.6 *ttydev = _getpty (&pfd, O_RDWR | O_NONBLOCK | O_NOCTTY, 0622, 0);
88 pcg 1.4 if (*ttydev != NULL)
89     return pfd;
90 pcg 1.1 #endif
91    
92     #if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
93 root 1.33 # if defined(PTYS_ARE_POSIX) || defined(PTYS_ARE_PTMX)
94 pcg 1.4
95     {
96 root 1.33 # ifdef PTYS_ARE_POSIX
97     pfd = posix_openpt (O_RDWR);
98 pcg 1.1 # else
99 pcg 1.6 pfd = open ("/dev/ptmx", O_RDWR | O_NOCTTY, 0);
100 pcg 1.1 # endif
101 pcg 1.4
102     if (pfd >= 0)
103     {
104 pcg 1.6 if (grantpt (pfd) == 0 /* change slave permissions */
105     && unlockpt (pfd) == 0)
106 pcg 1.4 { /* slave now unlocked */
107 root 1.16 *ttydev = strdup (ptsname (pfd)); /* get slave's name */
108 pcg 1.4 return pfd;
109     }
110 pcg 1.6 close (pfd);
111 pcg 1.4 }
112     }
113 pcg 1.1 # endif
114     #endif
115    
116     #ifdef PTYS_ARE_PTC
117 pcg 1.6 if ((pfd = open ("/dev/ptc", O_RDWR | O_NOCTTY, 0)) >= 0)
118 pcg 1.4 {
119 root 1.16 *ttydev = strdup (ttyname (pfd));
120 pcg 1.4 return pfd;
121 pcg 1.1 }
122     #endif
123    
124     #ifdef PTYS_ARE_CLONE
125 pcg 1.6 if ((pfd = open ("/dev/ptym/clone", O_RDWR | O_NOCTTY, 0)) >= 0)
126 pcg 1.4 {
127 root 1.16 *ttydev = strdup (ptsname (pfd));
128 pcg 1.4 return pfd;
129 pcg 1.1 }
130     #endif
131    
132     #ifdef PTYS_ARE_NUMERIC
133 pcg 1.4 {
134 root 1.16 int idx;
135     char *c1, *c2;
136     char pty_name[] = "/dev/ptyp???";
137     char tty_name[] = "/dev/ttyp???";
138 pcg 1.4
139 root 1.16 c1 = &(pty_name[sizeof (pty_name) - 4]);
140     c2 = &(tty_name[sizeof (tty_name) - 4]);
141 pcg 1.4 for (idx = 0; idx < 256; idx++)
142     {
143 pcg 1.6 sprintf (c1, "%d", idx);
144     sprintf (c2, "%d", idx);
145     if (access (tty_name, F_OK) < 0)
146 pcg 1.4 {
147     idx = 256;
148     break;
149     }
150 root 1.16
151 pcg 1.6 if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) >= 0)
152 pcg 1.4 {
153 pcg 1.6 if (access (tty_name, R_OK | W_OK) == 0)
154 pcg 1.4 {
155 pcg 1.6 *ttydev = strdup (tty_name);
156 pcg 1.4 return pfd;
157     }
158 root 1.16
159 pcg 1.6 close (pfd);
160 pcg 1.4 }
161     }
162     }
163 pcg 1.1 #endif
164 root 1.16
165 pcg 1.1 #ifdef PTYS_ARE_SEARCHED
166 pcg 1.4 {
167 root 1.16 const char *c1, *c2;
168     char pty_name[] = "/dev/pty??";
169     char tty_name[] = "/dev/tty??";
170 pcg 1.1
171     # ifndef PTYCHAR1
172     # define PTYCHAR1 "pqrstuvwxyz"
173     # endif
174     # ifndef PTYCHAR2
175     # define PTYCHAR2 "0123456789abcdef"
176     # endif
177 pcg 1.4
178     for (c1 = PTYCHAR1; *c1; c1++)
179     {
180 pcg 1.6 pty_name[ (sizeof (pty_name) - 3)] =
181     tty_name[ (sizeof (pty_name) - 3)] = *c1;
182 pcg 1.4 for (c2 = PTYCHAR2; *c2; c2++)
183     {
184 pcg 1.6 pty_name[ (sizeof (pty_name) - 2)] =
185     tty_name[ (sizeof (pty_name) - 2)] = *c2;
186     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) >= 0)
187 pcg 1.4 {
188 pcg 1.6 if (access (tty_name, R_OK | W_OK) == 0)
189 pcg 1.4 {
190 pcg 1.6 *ttydev = strdup (tty_name);
191 pcg 1.4 return pfd;
192     }
193 root 1.16
194 pcg 1.6 close (pfd);
195 pcg 1.4 }
196     }
197     }
198     }
199 pcg 1.1 #endif
200 root 1.16
201 pcg 1.4 return -1;
202 pcg 1.1 }
203    
204     /*----------------------------------------------------------------------*/
205     /*
206     * Returns tty file descriptor, or -1 on failure
207     */
208 root 1.16 static int
209     get_tty (char *ttydev)
210 pcg 1.1 {
211 pcg 1.4 return open (ttydev, O_RDWR | O_NOCTTY, 0);
212 pcg 1.1 }
213    
214     /*----------------------------------------------------------------------*/
215     /*
216     * Make our tty a controlling tty so that /dev/tty points to us
217     */
218 root 1.16 static int
219     control_tty (int fd_tty, const char *ttydev)
220 pcg 1.1 {
221     #ifndef __QNX__
222 pcg 1.4 int fd;
223 pcg 1.1
224 pcg 1.4 /* ---------------------------------------- */
225 pcg 1.1 # ifdef HAVE_SETSID
226 pcg 1.4 setsid ();
227 pcg 1.1 # endif
228     # if defined(HAVE_SETPGID)
229 pcg 1.4 setpgid (0, 0);
230 pcg 1.1 # elif defined(HAVE_SETPGRP)
231 pcg 1.4 setpgrp (0, 0);
232 pcg 1.1 # endif
233 root 1.16
234 pcg 1.4 /* ---------------------------------------- */
235 pcg 1.1 # ifdef TIOCNOTTY
236 pcg 1.4 fd = open ("/dev/tty", O_RDWR | O_NOCTTY);
237     if (fd >= 0)
238     {
239     ioctl (fd, TIOCNOTTY, NULL); /* void tty associations */
240     close (fd);
241 pcg 1.1 }
242     # endif
243 root 1.16
244 pcg 1.4 /* ---------------------------------------- */
245     fd = open ("/dev/tty", O_RDWR | O_NOCTTY);
246     if (fd >= 0)
247     close (fd); /* ouch: still have controlling tty */
248 root 1.16
249 pcg 1.4 /* ---------------------------------------- */
250 pcg 1.1 #if defined(PTYS_ARE_PTMX) && defined(I_PUSH)
251 pcg 1.4 /*
252     * Push STREAMS modules:
253     * ptem: pseudo-terminal hardware emulation module.
254     * ldterm: standard terminal line discipline.
255     * ttcompat: V7, 4BSD and XENIX STREAMS compatibility module.
256     *
257 pcg 1.6 * After we push the STREAMS modules, the first open () on the slave side
258 pcg 1.4 * (i.e. the next section between the dashes giving us "tty opened OK")
259     * should make the "ptem" (or "ldterm" depending upon either which OS
260     * version or which set of manual pages you have) module give us a
261 pcg 1.6 * controlling terminal. We must already have close ()d the master side
262 pcg 1.4 * fd in this child process before we push STREAMS modules on because the
263 pcg 1.6 * documentation is really unclear about whether it is any close () on
264     * the master side or the last close () - i.e. a proper STREAMS dismantling
265     * close () - on the master side which causes a hang up to be sent
266 pcg 1.4 * through - Geoff Wing
267     */
268 pcg 1.1 # ifdef HAVE_ISASTREAM
269 pcg 1.4 if (isastream (fd_tty) == 1)
270 pcg 1.1 # endif
271     {
272 pcg 1.4 ioctl (fd_tty, I_PUSH, "ptem");
273     ioctl (fd_tty, I_PUSH, "ldterm");
274     ioctl (fd_tty, I_PUSH, "ttcompat");
275 pcg 1.1 }
276     #endif
277 pcg 1.4 /* ---------------------------------------- */
278 pcg 1.1 # if defined(TIOCSCTTY)
279 pcg 1.4 fd = ioctl (fd_tty, TIOCSCTTY, NULL);
280 pcg 1.1 # elif defined(TIOCSETCTTY)
281 pcg 1.4 fd = ioctl (fd_tty, TIOCSETCTTY, NULL);
282 pcg 1.1 # else
283 pcg 1.4 fd = open (ttydev, O_RDWR);
284     if (fd >= 0)
285 pcg 1.6 close (fd);
286 pcg 1.1 # endif
287 pcg 1.4 /* ---------------------------------------- */
288     fd = open ("/dev/tty", O_WRONLY);
289     if (fd < 0)
290     return -1; /* fatal */
291     close (fd);
292     /* ---------------------------------------- */
293 pcg 1.1 #endif /* ! __QNX__ */
294 pcg 1.4
295     return 0;
296 pcg 1.1 }
297 root 1.16
298     #ifndef NO_SETOWNER_TTYDEV
299     static struct ttyconf {
300     gid_t gid;
301     mode_t mode;
302    
303     ttyconf ()
304     {
305     #ifdef TTY_GID_SUPPORT
306     struct group *gr = getgrnam ("tty");
307    
308     if (gr)
309     { /* change group ownership of tty to "tty" */
310     mode = S_IRUSR | S_IWUSR | S_IWGRP;
311     gid = gr->gr_gid;
312     }
313     else
314     #endif /* TTY_GID_SUPPORT */
315     {
316     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
317     gid = getgid ();
318     }
319     }
320     } ttyconf;
321    
322     void
323     rxvt_ptytty::privileges (rxvt_privaction action)
324     {
325 root 1.26 if (!name || !*name)
326 root 1.23 return;
327    
328 root 1.16 rxvt_privileges (RESTORE);
329    
330     if (action == SAVE)
331     {
332     # ifndef RESET_TTY_TO_COMMON_DEFAULTS
333     /* store original tty status for restoration rxvt_clean_exit () -- rgg 04/12/95 */
334     if (lstat (name, &savestat) < 0) /* you lose out */
335 root 1.26 ;
336 root 1.16 else
337     # endif
338     {
339 root 1.26 saved = true;
340 root 1.16 chown (name, getuid (), ttyconf.gid); /* fail silently */
341     chmod (name, ttyconf.mode);
342     # ifdef HAVE_REVOKE
343     revoke (name);
344     # endif
345     }
346     }
347     else
348     { /* action == RESTORE */
349     # ifndef RESET_TTY_TO_COMMON_DEFAULTS
350 root 1.26 if (saved)
351     {
352     chmod (name, savestat.st_mode);
353     chown (name, savestat.st_uid, savestat.st_gid);
354     }
355 root 1.16 # else
356     chmod (name, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
357     chown (name, 0, 0);
358     # endif
359    
360     }
361    
362     rxvt_privileges (IGNORE);
363     }
364     #endif
365    
366     rxvt_ptytty::rxvt_ptytty ()
367     {
368     pty = tty = -1;
369     name = 0;
370 root 1.26 #ifndef NO_SETOWNER_TTYDEV
371     saved = false;
372     #endif
373 root 1.16 }
374    
375     rxvt_ptytty::~rxvt_ptytty ()
376     {
377     put ();
378     }
379    
380     void
381    
382     rxvt_ptytty::close_tty ()
383     {
384 root 1.29 if (tty < 0)
385     return;
386    
387     close (tty);
388 root 1.16 tty = -1;
389     }
390    
391     void
392     rxvt_ptytty::put ()
393     {
394     #ifndef NO_SETOWNER_TTYDEV
395 root 1.28 privileges (RESTORE);
396 root 1.16 #endif
397    
398     if (pty >= 0) close (pty);
399     close_tty ();
400     free (name);
401    
402     pty = tty = -1;
403     name = 0;
404     }
405    
406     bool
407     rxvt_ptytty::make_controlling_tty ()
408     {
409     return control_tty (tty, name) >= 0;
410     }
411    
412     bool
413     rxvt_ptytty::get ()
414     {
415     /* get master (pty) */
416     if ((pty = get_pty (&tty, &name)) < 0)
417     return false;
418    
419     fcntl (pty, F_SETFL, O_NONBLOCK);
420    
421     /* get slave (tty) */
422     if (tty < 0)
423     {
424     #ifndef NO_SETOWNER_TTYDEV
425     privileges (SAVE);
426     #endif
427    
428     if ((tty = get_tty (name)) < 0)
429     {
430     put ();
431     return false;
432     }
433     }
434    
435     return true;
436     }
437    
438 root 1.22 void
439     rxvt_ptytty::set_utf8_mode (bool on)
440     {
441     #ifdef IUTF8
442 root 1.29 if (pty < 0)
443     return;
444    
445     struct termios tio;
446    
447     if (tcgetattr (pty, &tio) != -1)
448 root 1.22 {
449 root 1.29 tcflag_t new_cflag = tio.c_iflag;
450    
451     if (on)
452     new_cflag |= IUTF8;
453     else
454     new_cflag &= ~IUTF8;
455 root 1.22
456 root 1.29 if (new_cflag != tio.c_iflag)
457 root 1.22 {
458 root 1.29 tio.c_iflag = new_cflag;
459     tcsetattr (pty, TCSANOW, &tio);
460 root 1.22 }
461     }
462     #endif
463     }
464    
465 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
466 root 1.16