ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/ptytty.C
Revision: 1.39
Committed: Tue Jan 17 12:22:59 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.38: +8 -0 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 root 1.39 #include "ptytty.h"
60    
61 root 1.36 /////////////////////////////////////////////////////////////////////////////
62    
63 pcg 1.1 /* ------------------------------------------------------------------------- *
64     * GET PSEUDO TELETYPE - MASTER AND SLAVE *
65     * ------------------------------------------------------------------------- */
66     /*
67     * Returns pty file descriptor, or -1 on failure
68     * 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.16 static int
72     get_pty (int *fd_tty, char **ttydev)
73 pcg 1.1 {
74 pcg 1.4 int pfd;
75 pcg 1.1
76     #ifdef PTYS_ARE_OPENPTY
77 root 1.26 char tty_name[sizeof "/dev/pts/????\0"];
78 pcg 1.4
79 root 1.27 rxvt_privileges(RESTORE);
80     int res = openpty (&pfd, fd_tty, tty_name, NULL, NULL);
81     rxvt_privileges(IGNORE);
82    
83     if (res != -1)
84 pcg 1.4 {
85 pcg 1.6 *ttydev = strdup (tty_name);
86 pcg 1.4 return pfd;
87 pcg 1.1 }
88     #endif
89    
90     #ifdef PTYS_ARE__GETPTY
91 pcg 1.6 *ttydev = _getpty (&pfd, O_RDWR | O_NONBLOCK | O_NOCTTY, 0622, 0);
92 pcg 1.4 if (*ttydev != NULL)
93     return pfd;
94 pcg 1.1 #endif
95    
96     #if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
97 ayin 1.34 # if defined(PTYS_ARE_GETPT) || defined(PTYS_ARE_POSIX) || defined(PTYS_ARE_PTMX)
98 pcg 1.4
99     {
100 ayin 1.34 # ifdef PTYS_ARE_GETPT
101     pfd = getpt();
102     # else
103 root 1.33 # ifdef PTYS_ARE_POSIX
104     pfd = posix_openpt (O_RDWR);
105 pcg 1.1 # else
106 pcg 1.6 pfd = open ("/dev/ptmx", O_RDWR | O_NOCTTY, 0);
107 pcg 1.1 # endif
108 ayin 1.34 # endif
109 pcg 1.4
110     if (pfd >= 0)
111     {
112 pcg 1.6 if (grantpt (pfd) == 0 /* change slave permissions */
113     && unlockpt (pfd) == 0)
114 pcg 1.4 { /* slave now unlocked */
115 root 1.16 *ttydev = strdup (ptsname (pfd)); /* get slave's name */
116 pcg 1.4 return pfd;
117     }
118 pcg 1.6 close (pfd);
119 pcg 1.4 }
120     }
121 pcg 1.1 # endif
122     #endif
123    
124     #ifdef PTYS_ARE_PTC
125 pcg 1.6 if ((pfd = open ("/dev/ptc", O_RDWR | O_NOCTTY, 0)) >= 0)
126 pcg 1.4 {
127 root 1.16 *ttydev = strdup (ttyname (pfd));
128 pcg 1.4 return pfd;
129 pcg 1.1 }
130     #endif
131    
132     #ifdef PTYS_ARE_CLONE
133 pcg 1.6 if ((pfd = open ("/dev/ptym/clone", O_RDWR | O_NOCTTY, 0)) >= 0)
134 pcg 1.4 {
135 root 1.16 *ttydev = strdup (ptsname (pfd));
136 pcg 1.4 return pfd;
137 pcg 1.1 }
138     #endif
139    
140     #ifdef PTYS_ARE_NUMERIC
141 pcg 1.4 {
142 root 1.16 int idx;
143     char *c1, *c2;
144     char pty_name[] = "/dev/ptyp???";
145     char tty_name[] = "/dev/ttyp???";
146 pcg 1.4
147 root 1.16 c1 = &(pty_name[sizeof (pty_name) - 4]);
148     c2 = &(tty_name[sizeof (tty_name) - 4]);
149 pcg 1.4 for (idx = 0; idx < 256; idx++)
150     {
151 pcg 1.6 sprintf (c1, "%d", idx);
152     sprintf (c2, "%d", idx);
153     if (access (tty_name, F_OK) < 0)
154 pcg 1.4 {
155     idx = 256;
156     break;
157     }
158 root 1.16
159 pcg 1.6 if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) >= 0)
160 pcg 1.4 {
161 pcg 1.6 if (access (tty_name, R_OK | W_OK) == 0)
162 pcg 1.4 {
163 pcg 1.6 *ttydev = strdup (tty_name);
164 pcg 1.4 return pfd;
165     }
166 root 1.16
167 pcg 1.6 close (pfd);
168 pcg 1.4 }
169     }
170     }
171 pcg 1.1 #endif
172 root 1.16
173 pcg 1.1 #ifdef PTYS_ARE_SEARCHED
174 pcg 1.4 {
175 root 1.16 const char *c1, *c2;
176     char pty_name[] = "/dev/pty??";
177     char tty_name[] = "/dev/tty??";
178 pcg 1.1
179     # ifndef PTYCHAR1
180     # define PTYCHAR1 "pqrstuvwxyz"
181     # endif
182     # ifndef PTYCHAR2
183     # define PTYCHAR2 "0123456789abcdef"
184     # endif
185 pcg 1.4
186     for (c1 = PTYCHAR1; *c1; c1++)
187     {
188 pcg 1.6 pty_name[ (sizeof (pty_name) - 3)] =
189     tty_name[ (sizeof (pty_name) - 3)] = *c1;
190 pcg 1.4 for (c2 = PTYCHAR2; *c2; c2++)
191     {
192 pcg 1.6 pty_name[ (sizeof (pty_name) - 2)] =
193     tty_name[ (sizeof (pty_name) - 2)] = *c2;
194     if ((pfd = open (pty_name, O_RDWR | O_NOCTTY, 0)) >= 0)
195 pcg 1.4 {
196 pcg 1.6 if (access (tty_name, R_OK | W_OK) == 0)
197 pcg 1.4 {
198 pcg 1.6 *ttydev = strdup (tty_name);
199 pcg 1.4 return pfd;
200     }
201 root 1.16
202 pcg 1.6 close (pfd);
203 pcg 1.4 }
204     }
205     }
206     }
207 pcg 1.1 #endif
208 root 1.16
209 pcg 1.4 return -1;
210 pcg 1.1 }
211    
212     /*----------------------------------------------------------------------*/
213     /*
214     * Returns tty file descriptor, or -1 on failure
215     */
216 root 1.16 static int
217     get_tty (char *ttydev)
218 pcg 1.1 {
219 pcg 1.4 return open (ttydev, O_RDWR | O_NOCTTY, 0);
220 pcg 1.1 }
221    
222     /*----------------------------------------------------------------------*/
223     /*
224     * Make our tty a controlling tty so that /dev/tty points to us
225     */
226 root 1.16 static int
227 root 1.36 control_tty (int fd_tty)
228 pcg 1.1 {
229 pcg 1.4 int fd;
230 pcg 1.1
231 pcg 1.4 /* ---------------------------------------- */
232     setsid ();
233 root 1.16
234 pcg 1.4 /* ---------------------------------------- */
235 root 1.36 # if defined(PTYS_ARE_PTMX) && defined(I_PUSH)
236 pcg 1.4 /*
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 pcg 1.6 * After we push the STREAMS modules, the first open () on the slave side
243 pcg 1.4 * (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 pcg 1.6 * controlling terminal. We must already have close ()d the master side
247 pcg 1.4 * fd in this child process before we push STREAMS modules on because the
248 pcg 1.6 * 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 pcg 1.4 * through - Geoff Wing
252     */
253 root 1.36 # ifdef HAVE_ISASTREAM
254 pcg 1.4 if (isastream (fd_tty) == 1)
255 root 1.36 # endif
256 pcg 1.1 {
257 pcg 1.4 ioctl (fd_tty, I_PUSH, "ptem");
258     ioctl (fd_tty, I_PUSH, "ldterm");
259     ioctl (fd_tty, I_PUSH, "ttcompat");
260 pcg 1.1 }
261 root 1.36 # endif
262 pcg 1.4 /* ---------------------------------------- */
263     fd = ioctl (fd_tty, TIOCSCTTY, NULL);
264     /* ---------------------------------------- */
265     fd = open ("/dev/tty", O_WRONLY);
266     if (fd < 0)
267     return -1; /* fatal */
268     close (fd);
269     /* ---------------------------------------- */
270    
271     return 0;
272 pcg 1.1 }
273 root 1.16
274 root 1.36 void
275     rxvt_ptytty::close_tty ()
276     {
277     if (tty < 0)
278     return;
279    
280     close (tty);
281     tty = -1;
282     }
283    
284     bool
285     rxvt_ptytty::make_controlling_tty ()
286     {
287     return control_tty (tty) >= 0;
288     }
289    
290     void
291     rxvt_ptytty::set_utf8_mode (bool on)
292     {
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     /////////////////////////////////////////////////////////////////////////////
318    
319 root 1.16 #ifndef NO_SETOWNER_TTYDEV
320     static struct ttyconf {
321     gid_t gid;
322     mode_t mode;
323    
324     ttyconf ()
325     {
326     #ifdef TTY_GID_SUPPORT
327     struct group *gr = getgrnam ("tty");
328    
329     if (gr)
330     { /* change group ownership of tty to "tty" */
331     mode = S_IRUSR | S_IWUSR | S_IWGRP;
332     gid = gr->gr_gid;
333     }
334     else
335     #endif /* TTY_GID_SUPPORT */
336     {
337     mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
338     gid = getgid ();
339     }
340     }
341     } ttyconf;
342    
343 root 1.36 /////////////////////////////////////////////////////////////////////////////
344    
345 root 1.16 void
346 root 1.36 rxvt_ptytty_unix::privileges (rxvt_privaction action)
347 root 1.16 {
348 root 1.26 if (!name || !*name)
349 root 1.23 return;
350    
351 root 1.16 rxvt_privileges (RESTORE);
352    
353     if (action == SAVE)
354     {
355     # ifndef RESET_TTY_TO_COMMON_DEFAULTS
356     /* store original tty status for restoration rxvt_clean_exit () -- rgg 04/12/95 */
357     if (lstat (name, &savestat) < 0) /* you lose out */
358 root 1.26 ;
359 root 1.16 else
360     # endif
361     {
362 root 1.26 saved = true;
363 root 1.16 chown (name, getuid (), ttyconf.gid); /* fail silently */
364     chmod (name, ttyconf.mode);
365     # ifdef HAVE_REVOKE
366     revoke (name);
367     # endif
368     }
369     }
370     else
371     { /* action == RESTORE */
372     # ifndef RESET_TTY_TO_COMMON_DEFAULTS
373 root 1.26 if (saved)
374     {
375     chmod (name, savestat.st_mode);
376     chown (name, savestat.st_uid, savestat.st_gid);
377     }
378 root 1.16 # else
379     chmod (name, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
380     chown (name, 0, 0);
381     # endif
382    
383     }
384    
385     rxvt_privileges (IGNORE);
386     }
387     #endif
388    
389 root 1.36 rxvt_ptytty_unix::rxvt_ptytty_unix ()
390 root 1.16 {
391     pty = tty = -1;
392     name = 0;
393 root 1.26 #ifndef NO_SETOWNER_TTYDEV
394     saved = false;
395     #endif
396 root 1.35 #if UTMP_SUPPORT
397     cmd_pid = 0;
398     #endif
399 root 1.16 }
400    
401 root 1.36 rxvt_ptytty_unix::~rxvt_ptytty_unix ()
402 root 1.16 {
403 root 1.35 logout ();
404 root 1.16 put ();
405     }
406    
407     void
408 root 1.36 rxvt_ptytty_unix::put ()
409 root 1.16 {
410     #ifndef NO_SETOWNER_TTYDEV
411 root 1.28 privileges (RESTORE);
412 root 1.16 #endif
413    
414     if (pty >= 0) close (pty);
415     close_tty ();
416     free (name);
417    
418     pty = tty = -1;
419     name = 0;
420     }
421    
422     bool
423 root 1.36 rxvt_ptytty_unix::get ()
424 root 1.16 {
425     /* get master (pty) */
426     if ((pty = get_pty (&tty, &name)) < 0)
427     return false;
428    
429     fcntl (pty, F_SETFL, O_NONBLOCK);
430    
431     /* get slave (tty) */
432     if (tty < 0)
433     {
434     #ifndef NO_SETOWNER_TTYDEV
435     privileges (SAVE);
436     #endif
437    
438     if ((tty = get_tty (name)) < 0)
439     {
440     put ();
441     return false;
442     }
443     }
444    
445     return true;
446     }
447    
448 root 1.39 // a "factory" *g*
449     rxvt_ptytty *rxvt_new_ptytty ()
450     {
451     return new rxvt_ptytty_unix;
452     }
453    
454 pcg 1.1 /*----------------------- end-of-file (C source) -----------------------*/
455 root 1.16