File Coverage

blib/lib/IO/Pty.pm
Criterion Covered Total %
statement 48 93 51.6
branch 9 58 15.5
condition 1 2 50.0
subroutine 8 10 80.0
pod 5 5 100.0
total 71 168 42.2


line stmt bran cond sub pod time code
1             # Documentation at the __END__
2              
3             package IO::Pty;
4              
5 4     4   274004 use strict;
  4         47  
  4         124  
6 4     4   21 use Carp;
  4         9  
  4         244  
7 4     4   1687 use IO::Tty qw(TIOCSCTTY TCSETCTTY TIOCNOTTY);
  4         12  
  4         19  
8 4     4   28 use IO::File;
  4         10  
  4         460  
9             require POSIX;
10              
11 4     4   22 use vars qw(@ISA $VERSION);
  4         8  
  4         4344  
12              
13             $VERSION = '1.17'; # keep same as in Tty.pm
14              
15             @ISA = qw(IO::Handle);
16             eval { local $^W = 0; undef local $SIG{__DIE__}; require IO::Stty };
17             push @ISA, "IO::Stty" if ( not $@ ); # if IO::Stty is installed
18              
19             sub new {
20 6   50 6 1 2748794 my ($class) = $_[0] || "IO::Pty";
21 6 50       97 $class = ref($class) if ref($class);
22 6 50       87 @_ <= 1 or croak 'usage: new $class';
23              
24 6         4773 my ( $ptyfd, $ttyfd, $ttyname ) = pty_allocate();
25              
26 6 50       75 croak "Cannot open a pty" if not defined $ptyfd;
27              
28 6         293 my $pty = $class->SUPER::new_from_fd( $ptyfd, "r+" );
29 6 50       1439 croak "Cannot create a new $class from fd $ptyfd: $!" if not $pty;
30 6         141 $pty->autoflush(1);
31 6         574 bless $pty => $class;
32              
33 6         100 my $slave = IO::Tty->new_from_fd( $ttyfd, "r+" );
34 6 50       556 croak "Cannot create a new IO::Tty from fd $ttyfd: $!" if not $slave;
35 6         67 $slave->autoflush(1);
36              
37 6         217 ${*$pty}{'io_pty_slave'} = $slave;
  6         50  
38 6         44 ${*$pty}{'io_pty_ttyname'} = $ttyname;
  6         33  
39 6         21 ${*$slave}{'io_tty_ttyname'} = $ttyname;
  6         28  
40              
41 6         42 return $pty;
42             }
43              
44             sub ttyname {
45 0 0   0 1 0 @_ == 1 or croak 'usage: $pty->ttyname();';
46 0         0 my $pty = shift;
47 0         0 ${*$pty}{'io_pty_ttyname'};
  0         0  
48             }
49              
50             sub close_slave {
51 3 50   3 1 2662 @_ == 1 or croak 'usage: $pty->close_slave();';
52              
53 3         65 my $master = shift;
54              
55 3 50       30 if ( exists ${*$master}{'io_pty_slave'} ) {
  3         153  
56 3         28 close ${*$master}{'io_pty_slave'};
  3         50  
57 3         34 delete ${*$master}{'io_pty_slave'};
  3         212  
58             }
59             }
60              
61             sub slave {
62 2 50   2 1 965 @_ == 1 or croak 'usage: $pty->slave();';
63              
64 2         21 my $master = shift;
65              
66 2 50       12 if ( exists ${*$master}{'io_pty_slave'} ) {
  2         64  
67 2         18 return ${*$master}{'io_pty_slave'};
  2         25  
68             }
69              
70 0           my $tty = ${*$master}{'io_pty_ttyname'};
  0            
71              
72 0           my $slave = new IO::Tty;
73              
74 0 0         $slave->open( $tty, O_RDWR | O_NOCTTY )
75             || croak "Cannot open slave $tty: $!";
76              
77 0           return $slave;
78             }
79              
80             sub make_slave_controlling_terminal {
81 0 0   0 1   @_ == 1 or croak 'usage: $pty->make_slave_controlling_terminal();';
82              
83 0           my $self = shift;
84 0           local (*DEVTTY);
85              
86             # loose controlling terminal explicitly
87 0 0         if ( defined TIOCNOTTY ) {
88 0 0         if ( open( \*DEVTTY, "/dev/tty" ) ) {
89 0           ioctl( \*DEVTTY, TIOCNOTTY, 0 );
90 0           close \*DEVTTY;
91             }
92             }
93              
94             # Create a new 'session', lose controlling terminal.
95 0 0         if ( POSIX::setsid() == -1 ) {
96 0 0         warn "setsid() failed, strange behavior may result: $!\r\n" if $^W;
97             }
98              
99 0 0         if ( open( \*DEVTTY, "/dev/tty" ) ) {
100 0 0         warn "Could not disconnect from controlling terminal?!\n" if $^W;
101 0           close \*DEVTTY;
102             }
103              
104             # now open slave, this should set it as controlling tty on some systems
105 0           my $ttyname = ${*$self}{'io_pty_ttyname'};
  0            
106 0           my $slv = new IO::Tty;
107 0 0         $slv->open( $ttyname, O_RDWR )
108             or croak "Cannot open slave $ttyname: $!";
109              
110 0 0         if ( not exists ${*$self}{'io_pty_slave'} ) {
  0            
111 0           ${*$self}{'io_pty_slave'} = $slv;
  0            
112             }
113             else {
114 0           $slv->close;
115             }
116              
117             # Acquire a controlling terminal if this doesn't happen automatically
118 0 0         if ( not open( \*DEVTTY, "/dev/tty" ) ) {
119 0 0         if ( defined TIOCSCTTY ) {
    0          
120 0 0         if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TIOCSCTTY, 0 ) ) {
  0            
121 0 0         warn "warning: TIOCSCTTY failed, slave might not be set as controlling terminal: $!" if $^W;
122             }
123             }
124             elsif ( defined TCSETCTTY ) {
125 0 0         if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TCSETCTTY, 0 ) ) {
  0            
126 0 0         warn "warning: TCSETCTTY failed, slave might not be set as controlling terminal: $!" if $^W;
127             }
128             }
129             else {
130 0 0         warn "warning: You have neither TIOCSCTTY nor TCSETCTTY on your system\n" if $^W;
131 0           return 0;
132             }
133             }
134              
135 0 0         if ( not open( \*DEVTTY, "/dev/tty" ) ) {
136 0           warn "Error: could not connect pty as controlling terminal!\n";
137 0           return undef;
138             }
139             else {
140 0           close \*DEVTTY;
141             }
142              
143 0           return 1;
144             }
145              
146             *clone_winsize_from = \&IO::Tty::clone_winsize_from;
147             *get_winsize = \&IO::Tty::get_winsize;
148             *set_winsize = \&IO::Tty::set_winsize;
149             *set_raw = \&IO::Tty::set_raw;
150              
151             1;
152              
153             __END__