File Coverage

Tty.xs
Criterion Covered Total %
statement 78 199 39.2
branch 50 176 28.4
condition n/a
subroutine n/a
pod n/a
total 128 375 34.1


line stmt bran cond sub pod time code
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 .
40             *
41             * Nevertheless my references to Tatu Ylonen
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
49             #include
50             #include
51             #include
52             #include
53             #include
54             #include
55              
56             #ifdef HAVE_LIBUTIL_H
57             # include
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
65             # endif
66             #endif /* HAVE_UTIL_H */
67              
68             #ifdef HAVE_PTY_H
69             # include
70             #endif
71              
72             #ifdef HAVE_SYS_PTY_H
73             # include
74             #endif
75              
76             #ifdef HAVE_SYS_PTYIO_H
77             # include
78             #endif
79              
80             #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
81             # include
82             #endif
83              
84             #ifdef HAVE_TERMIOS_H
85             #include
86             #endif
87              
88             #ifdef HAVE_TERMIO_H
89             #include
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
124              
125             typedef void (*mysig_t)(int);
126              
127             static mysig_t
128 12           mysignal(int sig, mysig_t act)
129             {
130             #ifdef HAVE_SIGACTION
131             struct sigaction sa, osa;
132              
133 12 50         if (sigaction(sig, NULL, &osa) == -1)
134 0           return (mysig_t) -1;
135 12 50         if (osa.sa_handler != act) {
136 0           memset(&sa, 0, sizeof(sa));
137 0           sigemptyset(&sa.sa_mask);
138 0           sa.sa_flags = 0;
139             #if defined(SA_INTERRUPT)
140 0 0         if (sig == SIGALRM)
141 0           sa.sa_flags |= SA_INTERRUPT;
142             #endif
143 0           sa.sa_handler = act;
144 0 0         if (sigaction(sig, &sa, NULL) == -1)
145 0           return (mysig_t) -1;
146             }
147 12           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
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
190 0           strlcpy(dst, src, siz)
191             char *dst;
192             const char *src;
193             size_t siz;
194             {
195 0           register char *d = dst;
196 0           register const char *s = src;
197 0           register size_t n = siz;
198              
199             /* Copy as many bytes as will fit */
200 0 0         if (n != 0 && --n != 0) {
    0          
201             do {
202 0 0         if ((*d++ = *s++) == 0)
203 0           break;
204 0 0         } while (--n != 0);
205             }
206              
207             /* Not enough room in dst, add NUL and traverse rest of src */
208 0 0         if (n == 0) {
209 0 0         if (siz != 0)
210 0           *d = '\0'; /* NUL-terminate dst */
211 0 0         while (*s++)
212             ;
213             }
214              
215 0           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
225 12           make_safe_fd(int * fd)
226             {
227 12 100         if (*fd < 3) {
228             int newfd;
229 2           newfd = fcntl(*fd, F_DUPFD, 3);
230 2 50         if (newfd < 0) {
231 0 0         if (PL_dowarn)
232 0           warn("IO::Tty::pty_allocate(nonfatal): tried to move fd %d up but fcntl() said %.100s", *fd, strerror(errno));
233             } else {
234 2           close (*fd);
235 2           *fd = newfd;
236             }
237             }
238 12           }
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
250 6           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 6           old_signal = mysignal(SIGCHLD, SIG_DFL);
260             #if defined(HAVE_GRANTPT)
261             #if PTY_DEBUG
262 6 100         if (print_debug)
263 5           fprintf(stderr, "trying grantpt()...\n");
264             #endif
265 6 50         if (grantpt(*ptyfd) < 0) {
266 0 0         if (PL_dowarn)
267 0           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 6 100         if (print_debug)
274 5           fprintf(stderr, "trying unlockpt()...\n");
275             #endif
276 6 50         if (unlockpt(*ptyfd) < 0) {
277 0 0         if (PL_dowarn)
278 0           warn("IO::Tty::pty_allocate(nonfatal): unlockpt(): %.100s", strerror(errno));
279             }
280             #endif /* HAVE_UNLOCKPT */
281 6           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 6 50         if (namebuf[0] == 0) {
292             #if PTY_DEBUG
293 6 100         if (print_debug)
294 5           fprintf(stderr, "trying ptsname_r()...\n");
295             #endif
296 6 50         if(ptsname_r(*ptyfd, namebuf, namebuflen)) {
297 0 0         if (PL_dowarn)
298 0           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 6 50         if (namebuf[0] == 0) {
305             char * name;
306             #if PTY_DEBUG
307 0 0         if (print_debug)
308 0           fprintf(stderr, "trying ptsname()...\n");
309             #endif
310 0           name = ptsname(*ptyfd);
311 0 0         if (name) {
312 0 0         if(strlcpy(namebuf, name, namebuflen) >= namebuflen) {
313 0           warn("ERROR: IO::Tty::open_slave: ttyname truncated");
314 0           return 0;
315             }
316             } else {
317 0 0         if (PL_dowarn)
318 0           warn("IO::Tty::open_slave(nonfatal): ptsname(): %.100s", strerror(errno));
319             }
320             }
321             #endif /* HAVE_PTSNAME */
322              
323 6 50         if (namebuf[0] == 0)
324 0           return 0; /* we failed to get the slave name */
325              
326             #if defined (__SVR4) && defined (__sun)
327             #include
328             #include
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 6 50         if (*ttyfd >= 0) {
359 0           make_safe_fd(ptyfd);
360 0           make_safe_fd(ttyfd);
361 0           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 6 100         if (print_debug)
370 5           fprintf(stderr, "trying to open %s...\n", namebuf);
371             #endif
372              
373 6           *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
374 6 50         if (*ttyfd < 0) {
375 0 0         if (PL_dowarn)
376 0           warn("IO::Tty::open_slave(nonfatal): open(%.200s): %.100s",
377 0           namebuf, strerror(errno));
378 0           close(*ptyfd);
379 0           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 6 100         if (print_debug)
391 5           fprintf(stderr, "trying to I_PUSH ptem...\n");
392             #endif
393 6           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 6 100         if (print_debug)
402 5           fprintf(stderr, "trying to I_PUSH ldterm...\n");
403             #endif
404 6           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 6 100         if (print_debug)
413 5           fprintf(stderr, "trying to I_PUSH ttcompat...\n");
414             #endif
415 6           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 6           make_safe_fd(ptyfd);
431 6           make_safe_fd(ttyfd);
432              
433 6           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
447 6           allocate_pty(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
448             {
449 6           *ptyfd = -1;
450 6           *ttyfd = -1;
451 6           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 6 100         if (print_debug)
496 5           fprintf(stderr, "trying posix_openpt()...\n");
497             #endif
498 6           *ptyfd = posix_openpt(O_RDWR|O_NOCTTY);
499 6 50         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    50          
500 6           break; /* got one */
501 0 0         if (PL_dowarn)
502 0           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 0 0         if (print_debug)
509 0           fprintf(stderr, "trying getpt()...\n");
510             #endif
511 0           *ptyfd = getpt();
512 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
513 0           break; /* got one */
514 0 0         if (PL_dowarn)
515 0           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 0 0         if (print_debug)
552 0           fprintf(stderr, "trying /dev/ptmx...\n");
553             #endif
554              
555 0           *ptyfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
556 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
557 0           break;
558 0 0         if (PL_dowarn)
559 0           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 0           const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
716 0           const char *ptyminors = "0123456789abcdefghijklmnopqrstuv";
717 0           int num_minors = strlen(ptyminors);
718 0           int num_ptys = strlen(ptymajors) * num_minors;
719              
720             #if PTY_DEBUG
721 0 0         if (print_debug)
722 0           fprintf(stderr, "trying BSD /dev/pty??...\n");
723             #endif
724 0 0         for (i = 0; i < num_ptys; i++) {
725 0           sprintf(buf, "/dev/pty%c%c",
726 0           ptymajors[i / num_minors],
727 0           ptyminors[i % num_minors]);
728 0           sprintf(tbuf, "/dev/tty%c%c",
729 0           ptymajors[i / num_minors],
730 0           ptyminors[i % num_minors]);
731 0 0         if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
732 0           warn("ERROR: pty_allocate: ttyname truncated");
733 0           return 0;
734             }
735 0           *ptyfd = open(buf, O_RDWR | O_NOCTTY);
736 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
737 0           break;
738              
739             /* Try SCO style naming */
740 0           sprintf(buf, "/dev/ptyp%d", i);
741 0           sprintf(tbuf, "/dev/ttyp%d", i);
742 0 0         if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
743 0           warn("ERROR: pty_allocate: ttyname truncated");
744 0           return 0;
745             }
746 0           *ptyfd = open(buf, O_RDWR | O_NOCTTY);
747 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
748 0           break;
749              
750             /* Try BeOS style naming */
751 0           sprintf(buf, "/dev/pt/%c%c",
752 0           ptymajors[i / num_minors],
753 0           ptyminors[i % num_minors]);
754 0           sprintf(tbuf, "/dev/tt/%c%c",
755 0           ptymajors[i / num_minors],
756 0           ptyminors[i % num_minors]);
757 0 0         if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
758 0           warn("ERROR: pty_allocate: ttyname truncated");
759 0           return 0;
760             }
761 0           *ptyfd = open(buf, O_RDWR | O_NOCTTY);
762 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
763 0           break;
764              
765             /* Try z/OS style naming */
766 0           sprintf(buf, "/dev/ptyp%04d", i);
767 0           sprintf(tbuf, "/dev/ttyp%04d", i);
768 0 0         if (strlcpy(namebuf, tbuf, namebuflen) >= namebuflen) {
769 0           warn("ERROR: pty_allocate: ttyname truncated");
770 0           return 0;
771             }
772 0           *ptyfd = open(buf, O_RDWR | O_NOCTTY);
773 0 0         if (*ptyfd >= 0 && open_slave(ptyfd, ttyfd, namebuf, namebuflen))
    0          
774 0           break;
775              
776 0           namebuf[0] = 0;
777             }
778 0 0         if (*ptyfd >= 0)
779 0           break;
780             }
781              
782             } while (0);
783              
784 6 50         if (*ptyfd < 0 || namebuf[0] == 0)
    50          
785 0           return 0; /* we failed to allocate one */
786              
787 6           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 6           debug = perl_get_sv("IO::Tty::DEBUG", FALSE);
808 6 50         if (SvTRUE(debug))
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    100          
809 5           print_debug = 1;
810             #endif
811 6           ret = allocate_pty(&ptyfd, &ttyfd, name, sizeof(name));
812 6 50         if (ret) {
813 6           name[sizeof(name)-1] = 0;
814 6 50         EXTEND(SP,3);
815 6           PUSHs(sv_2mortal(newSViv(ptyfd)));
816 6           PUSHs(sv_2mortal(newSViv(ttyfd)));
817 6           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 0 0         if (handle)
831 0           RETVAL = ttyname(PerlIO_fileno(handle));
832             else {
833 0           RETVAL = Nullch;
834 0           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 4           ws.ws_row = row;
853 4           ws.ws_col = col;
854 4           ws.ws_xpixel = xpixel;
855 4           ws.ws_ypixel = ypixel;
856 4           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 1 50         if(SvCUR(winsize) != sizeof(ws))
867 0           croak("IO::Tty::unpack_winsize(): Bad arg length - got %d, expected %d",
868 0           SvCUR(winsize), sizeof(ws));
869 1 50         Copy(SvPV_nolen(winsize), &ws, sizeof(ws), char);
870 1 50         EXTEND(SP, 4);
871 1           PUSHs(sv_2mortal(newSViv(ws.ws_row)));
872 1           PUSHs(sv_2mortal(newSViv(ws.ws_col)));
873 1           PUSHs(sv_2mortal(newSViv(ws.ws_xpixel)));
874 1           PUSHs(sv_2mortal(newSViv(ws.ws_ypixel)));
875              
876              
877             BOOT:
878             {
879             HV *stash;
880             SV *config;
881              
882 4           stash = gv_stashpv("IO::Tty::Constant", TRUE);
883 4           config = perl_get_sv("IO::Tty::CONFIG", TRUE);
884             #include "xssubs.c"
885             }
886              
887