ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/libptytty/src/ptytty.C
Revision: 1.47
Committed: Wed Dec 21 11:07:22 2011 UTC (12 years, 6 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
CVS Tags: rel-9_14, rel-1_5
Changes since 1.46: +4 -0 lines
Log Message:
Define O_NOCTTY to 0 if it is not defined.

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