ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.33
Committed: Thu Dec 13 14:42:33 2007 UTC (16 years, 6 months ago) by ayin
Content type: text/plain
Branch: MAIN
Changes since 1.32: +5 -4 lines
Log Message:
Fix coding style.

File Contents

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