File Coverage

blib/lib/IO/Pty.pm
Criterion Covered Total %
statement 67 113 59.2
branch 13 52 25.0
condition 1 2 50.0
subroutine 10 11 90.9
pod 5 5 100.0
total 96 183 52.4


line stmt bran cond sub pod time code
1             # Documentation at the __END__
2              
3             package IO::Pty;
4              
5 10     10   817940 use strict;
  10         14  
  10         338  
6 10     10   39 use warnings;
  10         12  
  10         556  
7 10     10   42 use Carp;
  10         12  
  10         646  
8 10     10   3659 use IO::Tty qw(TIOCSCTTY TCSETCTTY TIOCNOTTY);
  10         25  
  10         32  
9 10     10   60 use IO::File;
  10         11  
  10         9865  
10             require POSIX;
11              
12             our @ISA = qw(IO::Handle);
13             our $VERSION = '1.31'; # keep same as in Tty.pm
14             eval { local $^W = 0; local $SIG{__DIE__}; require IO::Stty };
15             push @ISA, "IO::Stty" if ( not $@ ); # if IO::Stty is installed
16              
17             sub new {
18 22   50 22 1 1969055 my ($class) = $_[0] || "IO::Pty";
19 22 50       136 $class = ref($class) if ref($class);
20 22 50       120 @_ <= 1 or croak 'usage: new $class';
21              
22 22         3527 my ( $ptyfd, $ttyfd, $ttyname ) = pty_allocate();
23              
24 22 50       153 croak "Cannot open a pty" if not defined $ptyfd;
25              
26 22         542 my $pty = $class->SUPER::new_from_fd( $ptyfd, "r+" );
27 22 50       3147 if (not $pty) {
28 0         0 POSIX::close($ptyfd);
29 0         0 POSIX::close($ttyfd);
30 0         0 croak "Cannot create a new $class from fd $ptyfd: $!";
31             }
32 22         269 $pty->autoflush(1);
33 22         1032 bless $pty => $class;
34              
35 22         152 my $slave = IO::Tty->new_from_fd( $ttyfd, "r+" );
36 22 50       1229 if (not $slave) {
37 0         0 POSIX::close($ttyfd);
38 0         0 croak "Cannot create a new IO::Tty from fd $ttyfd: $!";
39             }
40 22         99 $slave->autoflush(1);
41              
42 22         508 ${*$pty}{'io_pty_slave'} = $slave;
  22         123  
43 22         63 ${*$pty}{'io_pty_ttyname'} = $ttyname;
  22         68  
44 22         74 ${*$slave}{'io_tty_ttyname'} = $ttyname;
  22         148  
45              
46 22         187 return $pty;
47             }
48              
49             sub ttyname {
50 2 50   2 1 459 @_ == 1 or croak 'usage: $pty->ttyname();';
51 2         2 my $pty = shift;
52 2         3 ${*$pty}{'io_pty_ttyname'};
  2         6  
53             }
54              
55             sub close_slave {
56 5 50   5 1 7222 @_ == 1 or croak 'usage: $pty->close_slave();';
57              
58 5         121 my $master = shift;
59              
60 5 50       29 if ( exists ${*$master}{'io_pty_slave'} ) {
  5         221  
61 5         60 close ${*$master}{'io_pty_slave'};
  5         106  
62 5         26 delete ${*$master}{'io_pty_slave'};
  5         291  
63             }
64             }
65              
66             sub slave {
67 20 50   20 1 3298 @_ == 1 or croak 'usage: $pty->slave();';
68              
69 20         65 my $master = shift;
70              
71 20 100       47 if ( exists ${*$master}{'io_pty_slave'} ) {
  20         125  
72 18         42 return ${*$master}{'io_pty_slave'};
  18         74  
73             }
74              
75 2         2 my $tty = ${*$master}{'io_pty_ttyname'};
  2         3  
76              
77 2         33 my $slave_fd = IO::Tty::_open_tty($tty);
78 2 50       7 croak "Cannot open slave $tty: $!" if $slave_fd < 0;
79              
80 2         7 my $slave = IO::Tty->new_from_fd( $slave_fd, "r+" );
81 2 50       97 if (not $slave) {
82 0         0 POSIX::close($slave_fd);
83 0         0 croak "Cannot create IO::Tty from fd $slave_fd: $!";
84             }
85 2         5 $slave->autoflush(1);
86              
87 2         49 ${*$slave}{'io_tty_ttyname'} = $tty;
  2         6  
88 2         2 ${*$master}{'io_pty_slave'} = $slave;
  2         4  
89              
90 2         4 return $slave;
91             }
92              
93             sub make_slave_controlling_terminal {
94 0 0   0 1 0 @_ == 1 or croak 'usage: $pty->make_slave_controlling_terminal();';
95              
96 0         0 my $self = shift;
97 0         0 local (*DEVTTY);
98              
99             # lose controlling terminal explicitly
100 0 0       0 if ( defined TIOCNOTTY ) {
101 0 0       0 if ( open( \*DEVTTY, "/dev/tty" ) ) {
102 0         0 ioctl( \*DEVTTY, TIOCNOTTY, 0 );
103 0         0 close \*DEVTTY;
104             }
105             }
106              
107             # Create a new 'session', lose controlling terminal.
108 0 0       0 if ( POSIX::setsid() == -1 ) {
109 0         0 warn "setsid() failed, strange behavior may result: $!\r\n";
110             }
111              
112 0 0       0 if ( open( \*DEVTTY, "/dev/tty" ) ) {
113 0         0 warn "Could not disconnect from controlling terminal?!\n";
114 0         0 close \*DEVTTY;
115             }
116              
117             # now open slave, this should set it as controlling tty on some systems
118             # Use _open_tty() to ensure STREAMS modules (ptem, ldterm, ttcompat)
119             # are pushed on Solaris/HP-UX. Pass noctty=0 so the open can
120             # automatically acquire a controlling terminal (the whole point of
121             # this method).
122 0         0 my $ttyname = ${*$self}{'io_pty_ttyname'};
  0         0  
123 0         0 my $slave_fd = IO::Tty::_open_tty($ttyname, 0);
124 0 0       0 croak "Cannot open slave $ttyname: $!" if $slave_fd < 0;
125 0         0 my $slv = IO::Tty->new_from_fd( $slave_fd, "r+" );
126 0 0       0 croak "Cannot create IO::Tty from fd $slave_fd: $!" if not $slv;
127 0         0 $slv->autoflush(1);
128              
129 0 0       0 if ( not exists ${*$self}{'io_pty_slave'} ) {
  0         0  
130 0         0 ${*$self}{'io_pty_slave'} = $slv;
  0         0  
131             }
132             else {
133 0         0 $slv->close;
134             }
135              
136             # Acquire a controlling terminal if this doesn't happen automatically
137 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
138 0 0       0 if ( defined TIOCSCTTY ) {
    0          
139 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TIOCSCTTY, 0 ) ) {
  0         0  
140 0         0 warn "warning: TIOCSCTTY failed, slave might not be set as controlling terminal: $!";
141             }
142             }
143             elsif ( defined TCSETCTTY ) {
144 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TCSETCTTY, 0 ) ) {
  0         0  
145 0         0 warn "warning: TCSETCTTY failed, slave might not be set as controlling terminal: $!";
146             }
147             }
148             else {
149 0         0 warn "warning: You have neither TIOCSCTTY nor TCSETCTTY on your system\n";
150 0         0 return 0;
151             }
152             }
153              
154 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
155 0         0 warn "Error: could not connect pty as controlling terminal!\n";
156 0         0 return undef;
157             }
158             else {
159 0         0 close \*DEVTTY;
160             }
161              
162 0         0 return 1;
163             }
164              
165             sub DESTROY {
166 22     22   6537112 my $self = shift;
167             # Only delete the internal reference; do not force-close the slave.
168             # Perl's refcounting will close the fd when no references remain.
169             # Force-closing here breaks consumers (e.g. IPC::Run) that hold
170             # their own reference to the slave obtained via $pty->slave().
171 22         50 delete ${*$self}{'io_pty_slave'};
  22         2374  
172             }
173              
174             *clone_winsize_from = \&IO::Tty::clone_winsize_from;
175             *get_winsize = \&IO::Tty::get_winsize;
176             *set_winsize = \&IO::Tty::set_winsize;
177             *set_raw = \&IO::Tty::set_raw;
178              
179             1;
180              
181             __END__