1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #define PTY_DEBUG 1
6
7 #ifdef PTY_DEBUG
8 static int print_debug;
9 #endif
10
11 #ifdef PerlIO
12 typedef int SysRet;
13 typedef PerlIO * InOutStream;
14 #else
15 # define PERLIO_IS_STDIO 1
16 # define PerlIO_fileno fileno
17 typedef int SysRet;
18 typedef FILE * InOutStream;
19 #endif
20
21 #include "patchlevel.h"
22
23 #if (PATCHLEVEL < 3) || ((PATCHLEVEL == 3) && (SUBVERSION < 22))
24 /* before 5.003_22 */
25 # define MY_start_subparse(fmt,flags) start_subparse()
26 #else
27 # if (PATCHLEVEL == 3) && (SUBVERSION == 22)
28 /* 5.003_22 */
29 # define MY_start_subparse(fmt,flags) start_subparse(flags)
30 # else
31 /* 5.003_23 onwards */
32 # define MY_start_subparse(fmt,flags) start_subparse(fmt,flags)
33 # endif
34 #endif
35
36 /*
37 * The following pty-allocation code was heavily inspired by its
38 * counterparts in openssh 3.0p1 and Xemacs 21.4.5 but is a complete
39 * rewrite by me, Roland Giersig <RGiersig@cpan.org>.
40 *
41 * Nevertheless my references to Tatu Ylonen <ylo@cs.hut.fi>
42 * and the Xemacs development team for their inspiring code.
43 *
44 * mysignal and strlcpy were borrowed from openssh and have their
45 * copyright messages attached.
46 */
47
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <fcntl.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/ioctl.h>
55
56 #ifdef HAVE_LIBUTIL_H
57 # include <libutil.h>
58 #endif /* HAVE_UTIL_H */
59
60 #ifdef HAVE_UTIL_H
61 # ifdef UTIL_H_ABS_PATH
62 # include UTIL_H_ABS_PATH
63 # elif ((PATCHLEVEL < 19) && (SUBVERSION < 4))
64 # include <util.h>
65 # endif
66 #endif /* HAVE_UTIL_H */
67
68 #ifdef HAVE_PTY_H
69 # include <pty.h>
70 #endif
71
72 #ifdef HAVE_SYS_PTY_H
73 # include <sys/pty.h>
74 #endif
75
76 #ifdef HAVE_SYS_PTYIO_H
77 # include <sys/ptyio.h>
78 #endif
79
80 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
81 # include <sys/stropts.h>
82 #endif
83
84 #ifdef HAVE_TERMIOS_H
85 #include <termios.h>
86 #endif
87
88 #ifdef HAVE_TERMIO_H
89 #include <termio.h>
90 #endif
91
92 #ifndef O_NOCTTY
93 #define O_NOCTTY 0
94 #endif
95
96
97 /* from $OpenBSD: misc.c,v 1.12 2001/06/26 17:27:24 markus Exp $ */
98
99 /*
100 * Copyright (c) 2000 Markus Friedl. All rights reserved.
101 *
102 * Redistribution and use in source and binary forms, with or without
103 * modification, are permitted provided that the following conditions
104 * are met:
105 * 1. Redistributions of source code must retain the above copyright
106 * notice, this list of conditions and the following disclaimer.
107 * 2. Redistributions in binary form must reproduce the above copyright
108 * notice, this list of conditions and the following disclaimer in the
109 * documentation and/or other materials provided with the distribution.
110 *
111 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
112 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
113 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
114 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
115 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
116 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
117 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
118 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
119 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
120 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
121 */
122
123 #include <signal.h>
124
125 typedef void (*mysig_t)(int);
126
127 static mysig_t
mysignal(int sig,mysig_t act)128 mysignal(int sig, mysig_t act)
129 {
130 #ifdef HAVE_SIGACTION
131 struct sigaction sa, osa;
132
133 if (sigaction(sig, NULL, &osa) == -1)
134 return (mysig_t) -1;
135 if (osa.sa_handler != act) {
136 memset(&sa, 0, sizeof(sa));
137 sigemptyset(&sa.sa_mask);
138 sa.sa_flags = 0;
139 #if defined(SA_INTERRUPT)
140 if (sig == SIGALRM)
141 sa.sa_flags |= SA_INTERRUPT;
142 #endif
143 sa.sa_handler = act;
144 if (sigaction(sig, &sa, NULL) == -1)
145 return (mysig_t) -1;
146 }
147 return (osa.sa_handler);
148 #else
149 return (signal(sig, act));
150 #endif
151 }
152
153 /* from $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
154
155 /*
156 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
157 * All rights reserved.
158 *
159 * Redistribution and use in source and binary forms, with or without
160 * modification, are permitted provided that the following conditions
161 * are met:
162 * 1. Redistributions of source code must retain the above copyright
163 * notice, this list of conditions and the following disclaimer.
164 * 2. Redistributions in binary form must reproduce the above copyright
165 * notice, this list of conditions and the following disclaimer in the
166 * documentation and/or other materials provided with the distribution.
167 * 3. The name of the author may not be used to endorse or promote products
168 * derived from this software without specific prior written permission.
169 *
170 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
171 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
172 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
173 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
174 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
175 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
176 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
177 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
178 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
179 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
180 */
181
182 #ifndef HAVE_STRLCPY
183
184 /*
185 * Copy src to string dst of size siz. At most siz-1 characters
186 * will be copied. Always NUL terminates (unless siz == 0).
187 * Returns strlen(src); if retval >= siz, truncation occurred.
188 */
189 static size_t
strlcpy(dst,src,siz)190 strlcpy(dst, src, siz)
191 char *dst;
192 const char *src;
193 size_t siz;
194 {
195 register char *d = dst;
196 register const char *s = src;
197 register size_t n = siz;
198
199 /* Copy as many bytes as will fit */
200 if (n != 0 && --n != 0) {
201 do {
202 if ((*d++ = *s++) == 0)
203 break;
204 } while (--n != 0);
205 }
206
207 /* Not enough room in dst, add NUL and traverse rest of src */
208 if (n == 0) {
209 if (siz != 0)
210 *d = '\0'; /* NUL-terminate dst */
211 while (*s++)
212 ;
213 }
214
215 return(s - src - 1); /* count does not include NUL */
216 }
217
218 #endif /* !HAVE_STRLCPY */
219
220 /*
221 * Move file descriptor so it doesn't collide with stdin/out/err
222 */
223
224 static void
make_safe_fd(int * fd)225 make_safe_fd(int * fd)
226 {
227 if (*fd < 3) {
228 int newfd;
229 newfd = fcntl(*fd, F_DUPFD, 3);
230 if (newfd < 0) {
231 if (PL_dowarn)
232 warn("IO::Tty::pty_allocate(nonfatal): tried to move fd %d up but fcntl() said %.100s", *fd, strerror(errno));
233 } else {
234 close (*fd);
235 *fd = newfd;
236 }
237 }
238 }
239
240 /*
241 * After having acquired a master pty, try to find out the slave name,
242 * initialize and open the slave.
243 */
244
245 #if defined (HAVE_PTSNAME)
246 char * ptsname(int);
247 #endif
248
249 static int
open_slave(int * ptyfd,int * ttyfd,char * namebuf,int namebuflen)250 open_slave(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
251 {
252 /*
253 * now do some things that are supposedly healthy for ptys,
254 * i.e. changing the access mode.
255 */
256 #if defined(HAVE_GRANTPT) || defined(HAVE_UNLOCKPT)
257 {
258 mysig_t old_signal;
259 old_signal = mysignal(SIGCHLD, SIG_DFL);
260 #if defined(HAVE_GRANTPT)
261 #if PTY_DEBUG
262 if (print_debug)
263 fprintf(stderr, "trying grantpt()...\n");
264 #endif
265 if (grantpt(*ptyfd) < 0) {
266 if (PL_dowarn)
267 warn("IO::Tty::pty_allocate(nonfatal): grantpt(): %.100s", strerror(errno));
268 }
269
270 #endif /* HAVE_GRANTPT */
271 #if defined(HAVE_UNLOCKPT)
272 #if PTY_DEBUG
273 if (print_debug)
274 fprintf(stderr, "trying unlockpt()...\n");
275 #endif
276 if (unlockpt(*ptyfd) < 0) {
277 if (PL_dowarn)
278 warn("IO::Tty::pty_allocate(nonfatal): unlockpt(): %.100s", strerror(errno));
279 }
280 #endif /* HAVE_UNLOCKPT */
281 mysignal(SIGCHLD, old_signal);
282 }
283 #endif /* HAVE_GRANTPT || HAVE_UNLOCKPT */
284
285
286 /*
287 * find the slave name, if we don't have it already
288 */
289
290 #if defined (HAVE_PTSNAME_R)
291 if (namebuf[0] == 0) {
292 #if PTY_DEBUG
293 if (print_debug)
294 fprintf(stderr, "trying ptsname_r()...\n");
295 #endif
296 if(ptsname_r(*ptyfd, namebuf, namebuflen)) {
297 if (PL_dowarn)
298 warn("IO::Tty::open_slave(nonfatal): ptsname_r(): %.100s", strerror(errno));
299 }
300 }
301 #endif /* HAVE_PTSNAME_R */
302
303 #if defined (HAVE_PTSNAME)
304 if (namebuf[0] == 0) {
305 char * name;
306 #if PTY_DEBUG
307 if (print_debug)
308 fprintf(stderr, "trying ptsname()...\n");
309 #endif
310 name = ptsname(*ptyfd);
311 if (name) {
312 if(strlcpy(namebuf, name, namebuflen) >= namebuflen) {
313 warn("ERROR: IO::Tty::open_slave: ttyname truncated");
314 return 0;
315 }
316 } else {
317 if (PL_dowarn)
318 warn("IO::Tty::open_slave(nonfatal): ptsname(): %.100s", strerror(errno));
319 }
320 }
321 #endif /* HAVE_PTSNAME */
322
323 if (namebuf[0] == 0)
324 return 0; /* we failed to get the slave name */
325
326 #if defined (__SVR4) && defined (__sun)
327 #include <sys/types.h>
328 #include <unistd.h>
329 {
330 uid_t euid = geteuid();
331 uid_t uid = getuid();
332
333 /* root running as another user
334 * grantpt() has done the wrong thing
335 */
336 if (euid != uid && uid == 0) {
337 #if PTY_DEBUG
338 if (print_debug)
339 fprintf(stderr, "trying seteuid() from %d to %d...\n",
340 euid, uid);
341 #endif
342 if (setuid(uid)) {
343 warn("ERROR: IO::Tty::open_slave: couldn't seteuid to root: %d", errno);
344 return 0;
345 }
346 if (chown(namebuf, euid, -1)) {
347 warn("ERROR: IO::Tty::open_slave: couldn't fchown the pty: %d", errno);
348 return 0;
349 }
350 if (seteuid(euid)) {
351 warn("ERROR: IO::Tty::open_slave: couldn't seteuid back: %d", errno);
352 return 0;
353 }
354 }
355 }
356 #endif
357
358 if (*ttyfd >= 0) {
359 make_safe_fd(ptyfd);
360 make_safe_fd(ttyfd);
361 return 1; /* we already have an open slave, so
362 no more init is needed */
363 }
364
365 /*
366 * Open the slave side.
367 */
368 #if PTY_DEBUG
369 if (print_debug)
370 fprintf(stderr, "trying to open %s...\n", namebuf);
371 #endif
372
373 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
374 if (*ttyfd < 0) {
375 if (PL_dowarn)
376 warn("IO::Tty::open_slave(nonfatal): open(%.200s): %.100s",
377 namebuf, strerror(errno));
378 close(*ptyfd);
379 return 0; /* too bad, couldn't open slave side */
380 }
381
382 #if defined (I_PUSH)
383 /*
384 * Push appropriate streams modules for Solaris pty(7).
385 * HP-UX pty(7) doesn't have ttcompat module.
386 * We simply try to push all relevant modules but warn only on
387 * those platforms we know these are required.
388 */
389 #if PTY_DEBUG
390 if (print_debug)
391 fprintf(stderr, "trying to I_PUSH ptem...\n");
392 #endif
393 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
394 #if defined (__solaris) || defined(__hpux)
395 if (PL_dowarn)
396 warn("IO::Tty::pty_allocate: ioctl I_PUSH ptem: %.100s", strerror(errno))
397 #endif
398 ;
399
400 #if PTY_DEBUG
401 if (print_debug)
402 fprintf(stderr, "trying to I_PUSH ldterm...\n");
403 #endif
404 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
405 #if defined (__solaris) || defined(__hpux)
406 if (PL_dowarn)
407 warn("IO::Tty::pty_allocate: ioctl I_PUSH ldterm: %.100s", strerror(errno))
408 #endif
409 ;
410
411 #if PTY_DEBUG
412 if (print_debug)
413 fprintf(stderr, "trying to I_PUSH ttcompat...\n");
414 #endif
415 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
416 #if defined (__solaris)
417 if (PL_dowarn)
418 warn("IO::Tty::pty_allocate: ioctl I_PUSH ttcompat: %.100s", strerror(errno))
419 #endif
420 ;
421 #endif /* I_PUSH */
422
423 /* finally we make sure the filedescriptors are > 2 to avoid
424 problems with stdin/out/err. This can happen if the user
425 closes one of them before allocating a pty and leads to nasty
426 side-effects, so we take a proactive stance here. Normally I
427 would say "Those who mess with stdin/out/err shall bear the
428 consequences to the fullest" but hey, I'm a nice guy... ;O) */
429
430 make_safe_fd(ptyfd);
431 make_safe_fd(ttyfd);
432
433 return 1;
434 }
435
436 /*
437 * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
438 * nonzero if a pty was successfully allocated. On success, open file
439 * descriptors for the pty and tty sides and the name of the tty side are
440 * returned (the buffer must be able to hold at least 64 characters).
441 *
442 * Instead of trying just one method we go through all available
443 * methods until we get a positive result.
444 */
445
446 static int
allocate_pty(int * ptyfd,int * ttyfd,char * namebuf,int namebuflen)447 allocate_pty(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
448 {
449 *ptyfd = -1;
450 *ttyfd = -1;
451 namebuf[0] = 0;
452
453 /*
454 * first we try to get a master device
455 */
456 do { /* we use do{}while(0) and break instead of goto */
457
458 #if defined(HAVE__GETPTY)
459 /* _getpty(3) for SGI Irix */
460 {
461 char *slave;
462 mysig_t old_signal;
463
464 #if PTY_DEBUG
465 if (print_debug)
466 fprintf(stderr, "trying _getpty()...\n");
467 #endif
468 /* _getpty spawns a suid prog, so don't ignore SIGCHLD */
469 old_signal = mysignal(SIGCHLD, SIG_DFL);
470 slave = _getpty(ptyfd, O_RDWR, 0622, 0);
471 mysignal(SIGCHLD, old_signal);
472
473 if (slave != NULL) {
474 if (strlcpy(namebuf, slave, namebuflen) >= namebuflen) {
475 warn("ERROR: pty_allocate: ttyname truncated");
476 return 0;
477 }
478 if (open_slave(ptyfd, ttyfd, namebuf, namebuflen))
479 break;
480 close(*ptyfd);
481 *ptyfd = -1;
482 } else {
483 if (PL_dowarn)
484 warn("pty_allocate(nonfatal): _getpty(): %.100s", strerror(errno));
485 *ptyfd = -1;
486 }
487 }
488 #endif
489
490 #if defined(HAVE_PTSNAME) || defined(HAVE_PTSNAME_R)
491 /* we don't need to try these if we don't have a way to get the pty names */
492
493 #if defined(HAVE_POSIX_OPENPT)
494 #if PTY_DEBUG
495 if (print_debug)
496 fprintf(stderr, "trying posix_openpt()...\n");
497 #endif
498 *ptyfd = posix_openpt(O_RDWR|O_NOCTTY);
499 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
500 break; /* got one */
501 if (PL_dowarn)
502 warn("pty_allocate(nonfatal): posix_openpt(): %.100s", strerror(errno));
503 #endif /* defined(HAVE_POSIX_OPENPT) */
504
505 #if defined(HAVE_GETPT)
506 /* glibc defines this */
507 #if PTY_DEBUG
508 if (print_debug)
509 fprintf(stderr, "trying getpt()...\n");
510 #endif
511 *ptyfd = getpt();
512 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
513 break; /* got one */
514 if (PL_dowarn)
515 warn("pty_allocate(nonfatal): getpt(): %.100s", strerror(errno));
516 #endif /* defined(HAVE_GETPT) */
517
518 #if defined(HAVE_OPENPTY)
519 /* openpty(3) exists in a variety of OS'es, but due to it's
520 * broken interface (no maxlen to slavename) we'll only use it
521 * to create the tty/pty pair and rely on ptsname to get the
522 * name. */
523 {
524 mysig_t old_signal;
525 int ret;
526
527 #if PTY_DEBUG
528 if (print_debug)
529 fprintf(stderr, "trying openpty()...\n");
530 #endif
531 old_signal = mysignal(SIGCHLD, SIG_DFL);
532 ret = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
533 mysignal(SIGCHLD, old_signal);
534 if (ret >= 0 && *ptyfd >= 0) {
535 if (open_slave(ptyfd, ttyfd, namebuf, namebuflen))
536 break;
537 }
538 *ptyfd = -1;
539 *ttyfd = -1;
540 if (PL_dowarn)
541 warn("pty_allocate(nonfatal): openpty(): %.100s", strerror(errno));
542 }
543 #endif /* defined(HAVE_OPENPTY) */
544
545 /*
546 * now try various cloning devices
547 */
548
549 #if defined(HAVE_DEV_PTMX)
550 #if PTY_DEBUG
551 if (print_debug)
552 fprintf(stderr, "trying /dev/ptmx...\n");
553 #endif
554
555 *ptyfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
556 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
557 break;
558 if (PL_dowarn)
559 warn("pty_allocate(nonfatal): open(/dev/ptmx): %.100s", strerror(errno));
560 #endif /* HAVE_DEV_PTMX */
561
562 #if defined(HAVE_DEV_PTYM_CLONE)
563 #if PTY_DEBUG
564 if (print_debug)
565 fprintf(stderr, "trying /dev/ptym/clone...\n");
566 #endif
567
568 *ptyfd = open("/dev/ptym/clone", O_RDWR | O_NOCTTY);
569 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
570 break;
571 if (PL_dowarn)
572 warn("pty_allocate(nonfatal): open(/dev/ptym/clone): %.100s", strerror(errno));
573 #endif /* HAVE_DEV_PTYM_CLONE */
574
575 #if defined(HAVE_DEV_PTC)
576 /* AIX-style pty code. */
577 #if PTY_DEBUG
578 if (print_debug)
579 fprintf(stderr, "trying /dev/ptc...\n");
580 #endif
581
582 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
583 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
584 break;
585 if (PL_dowarn)
586 warn("pty_allocate(nonfatal): open(/dev/ptc): %.100s", strerror(errno));
587 #endif /* HAVE_DEV_PTC */
588
589 #if defined(HAVE_DEV_PTMX_BSD)
590 #if PTY_DEBUG
591 if (print_debug)
592 fprintf(stderr, "trying /dev/ptmx_bsd...\n");
593 #endif
594 *ptyfd = open("/dev/ptmx_bsd", O_RDWR | O_NOCTTY);
595 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
596 break;
597 if (PL_dowarn)
598 warn("pty_allocate(nonfatal): open(/dev/ptmx_bsd): %.100s", strerror(errno));
599 #endif /* HAVE_DEV_PTMX_BSD */
600
601 #endif /* !defined(HAVE_PTSNAME) && !defined(HAVE_PTSNAME_R) */
602
603 /*
604 * we still don't have a pty, so try some oldfashioned stuff,
605 * looking for a pty/tty pair ourself.
606 */
607
608 #if defined(_CRAY)
609 {
610 char buf[64];
611 int i;
612 int highpty;
613
614 #ifdef _SC_CRAY_NPTY
615 highpty = sysconf(_SC_CRAY_NPTY);
616 if (highpty == -1)
617 highpty = 128;
618 #else
619 highpty = 128;
620 #endif
621 #if PTY_DEBUG
622 if (print_debug)
623 fprintf(stderr, "trying CRAY /dev/pty/???...\n");
624 #endif
625 for (i = 0; i < highpty; i++) {
626 sprintf(buf, "/dev/pty/%03d", i);
627 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
628 if (*ptyfd < 0)
629 continue;
630 sprintf(buf, "/dev/ttyp%03d", i);
631 if (strlcpy(namebuf, buf, namebuflen) >= namebuflen) {
632 warn("ERROR: pty_allocate: ttyname truncated");
633 return 0;
634 }
635 break;
636 }
637 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
638 break;
639 }
640 #endif
641
642 #if defined(HAVE_DEV_PTYM)
643 {
644 /* HPUX */
645 char buf[64];
646 char tbuf[64];
647 int i;
648 struct stat sb;
649 const char *ptymajors = "abcefghijklmnopqrstuvwxyz";
650 const char *ptyminors = "0123456789abcdef";
651 int num_minors = strlen(ptyminors);
652 int num_ptys = strlen(ptymajors) * num_minors;
653
654 #if PTY_DEBUG
655 if (print_debug)
656 fprintf(stderr, "trying HPUX /dev/ptym/pty[a-ce-z][0-9a-f]...\n");
657 #endif
658 /* try /dev/ptym/pty[a-ce-z][0-9a-f] */
659 for (i = 0; i < num_ptys; i++) {
660 sprintf(buf, "/dev/ptym/pty%c%c",
661 ptymajors[i / num_minors],
662 ptyminors[i % num_minors]);
663 sprintf(tbuf, "/dev/pty/tty%c%c",
664 ptymajors[i / num_minors],
665 ptyminors[i % num_minors]);
666 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
667 warn("ERROR: pty_allocate: ttyname truncated");
668 return 0;
669 }
670 if(stat(buf, &sb))
671 break; /* file does not exist, skip rest */
672 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
673 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
674 break;
675 namebuf[0] = 0;
676 }
677 if (*ptyfd >= 0)
678 break;
679
680 #if PTY_DEBUG
681 if (print_debug)
682 fprintf(stderr, "trying HPUX /dev/ptym/pty[a-ce-z][0-9][0-9]...\n");
683 #endif
684 /* now try /dev/ptym/pty[a-ce-z][0-9][0-9] */
685 num_minors = 100;
686 num_ptys = strlen(ptymajors) * num_minors;
687 for (i = 0; i < num_ptys; i++) {
688 sprintf(buf, "/dev/ptym/pty%c%02d",
689 ptymajors[i / num_minors],
690 i % num_minors);
691 sprintf(tbuf, "/dev/pty/tty%c%02d",
692 ptymajors[i / num_minors], i % num_minors);
693 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
694 warn("ERROR: pty_allocate: ttyname truncated");
695 return 0;
696 }
697
698 if(stat(buf, &sb))
699 break; /* file does not exist, skip rest */
700 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
701 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
702 break;
703 namebuf[0] = 0;
704 }
705 if (*ptyfd >= 0)
706 break;
707 }
708 #endif /* HAVE_DEV_PTYM */
709
710 {
711 /* BSD-style pty code. */
712 char buf[64];
713 char tbuf[64];
714 int i;
715 const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
716 const char *ptyminors = "0123456789abcdefghijklmnopqrstuv";
717 int num_minors = strlen(ptyminors);
718 int num_ptys = strlen(ptymajors) * num_minors;
719
720 #if PTY_DEBUG
721 if (print_debug)
722 fprintf(stderr, "trying BSD /dev/pty??...\n");
723 #endif
724 for (i = 0; i < num_ptys; i++) {
725 sprintf(buf, "/dev/pty%c%c",
726 ptymajors[i / num_minors],
727 ptyminors[i % num_minors]);
728 sprintf(tbuf, "/dev/tty%c%c",
729 ptymajors[i / num_minors],
730 ptyminors[i % num_minors]);
731 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
732 warn("ERROR: pty_allocate: ttyname truncated");
733 return 0;
734 }
735 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
736 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
737 break;
738
739 /* Try SCO style naming */
740 sprintf(buf, "/dev/ptyp%d", i);
741 sprintf(tbuf, "/dev/ttyp%d", i);
742 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
743 warn("ERROR: pty_allocate: ttyname truncated");
744 return 0;
745 }
746 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
747 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
748 break;
749
750 /* Try BeOS style naming */
751 sprintf(buf, "/dev/pt/%c%c",
752 ptymajors[i / num_minors],
753 ptyminors[i % num_minors]);
754 sprintf(tbuf, "/dev/tt/%c%c",
755 ptymajors[i / num_minors],
756 ptyminors[i % num_minors]);
757 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
758 warn("ERROR: pty_allocate: ttyname truncated");
759 return 0;
760 }
761 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
762 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
763 break;
764
765 /* Try z/OS style naming */
766 sprintf(buf, "/dev/ptyp%04d", i);
767 sprintf(tbuf, "/dev/ttyp%04d", i);
768 if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
769 warn("ERROR: pty_allocate: ttyname truncated");
770 return 0;
771 }
772 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
773 if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
774 break;
775
776 namebuf[0] = 0;
777 }
778 if (*ptyfd >= 0)
779 break;
780 }
781
782 } while (0);
783
784 if (*ptyfd < 0 || namebuf[0] == 0)
785 return 0; /* we failed to allocate one */
786
787 return 1; /* whew, finally finished successfully */
788 } /* end allocate_pty */
789
790
791
792 MODULE = IO::Tty PACKAGE = IO::Pty
793
794 PROTOTYPES: DISABLE
795
796 void
797 pty_allocate()
798 INIT:
799 int ptyfd, ttyfd, ret;
800 char name[256];
801 #ifdef PTY_DEBUG
802 SV *debug;
803 #endif
804
805 PPCODE:
806 #ifdef PTY_DEBUG
807 debug = perl_get_sv("IO::Tty::DEBUG", FALSE);
808 if (SvTRUE(debug))
809 print_debug = 1;
810 #endif
811 ret = allocate_pty(&ptyfd, &ttyfd, name, sizeof(name));
812 if (ret) {
813 name[sizeof(name)-1] = 0;
814 EXTEND(SP,3);
815 PUSHs(sv_2mortal(newSViv(ptyfd)));
816 PUSHs(sv_2mortal(newSViv(ttyfd)));
817 PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
818 } else {
819 /* empty list */
820 }
821
822
823 MODULE = IO::Tty PACKAGE = IO::Tty
824
825 char *
826 ttyname(handle)
827 InOutStream handle
828 CODE:
829 #ifdef HAVE_TTYNAME
830 if (handle)
831 RETVAL = ttyname(PerlIO_fileno(handle));
832 else {
833 RETVAL = Nullch;
834 errno = EINVAL;
835 }
836 #else
837 warn("IO::Tty::ttyname not implemented on this architecture");
838 RETVAL = Nullch;
839 #endif
840 OUTPUT:
841 RETVAL
842
843 SV *
844 pack_winsize(row, col, xpixel = 0, ypixel = 0)
845 int row
846 int col
847 int xpixel
848 int ypixel
849 INIT:
850 struct winsize ws;
851 CODE:
852 ws.ws_row = row;
853 ws.ws_col = col;
854 ws.ws_xpixel = xpixel;
855 ws.ws_ypixel = ypixel;
856 RETVAL = newSVpvn((char *)&ws, sizeof(ws));
857 OUTPUT:
858 RETVAL
859
860 void
861 unpack_winsize(winsize)
862 SV *winsize;
863 INIT:
864 struct winsize ws;
865 PPCODE:
866 if(SvCUR(winsize) != sizeof(ws))
867 croak("IO::Tty::unpack_winsize(): Bad arg length - got %d, expected %d",
868 SvCUR(winsize), sizeof(ws));
869 Copy(SvPV_nolen(winsize), &ws, sizeof(ws), char);
870 EXTEND(SP, 4);
871 PUSHs(sv_2mortal(newSViv(ws.ws_row)));
872 PUSHs(sv_2mortal(newSViv(ws.ws_col)));
873 PUSHs(sv_2mortal(newSViv(ws.ws_xpixel)));
874 PUSHs(sv_2mortal(newSViv(ws.ws_ypixel)));
875
876
877 BOOT:
878 {
879 HV *stash;
880 SV *config;
881
882 stash = gv_stashpv("IO::Tty::Constant", TRUE);
883 config = perl_get_sv("IO::Tty::CONFIG", TRUE);
884 #include "xssubs.c"
885 }
886
887
888