File Coverage

Tty.xs
Criterion Covered Total %
statement 75 200 37.5
branch 36 142 25.3
condition n/a
subroutine n/a
pod n/a
total 111 342 32.4


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