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   890100 use strict;
  10         18  
  10         302  
6 10     10   38 use warnings;
  10         13  
  10         436  
7 10     10   41 use Carp;
  10         15  
  10         564  
8 10     10   3659 use IO::Tty qw(TIOCSCTTY TCSETCTTY TIOCNOTTY);
  10         27  
  10         34  
9 10     10   82 use IO::File;
  10         16  
  10         10215  
10             require POSIX;
11              
12             our @ISA = qw(IO::Handle);
13             our $VERSION = '1.29'; # 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 2189532 my ($class) = $_[0] || "IO::Pty";
19 22 50       163 $class = ref($class) if ref($class);
20 22 50       100 @_ <= 1 or croak 'usage: new $class';
21              
22 22         3568 my ( $ptyfd, $ttyfd, $ttyname ) = pty_allocate();
23              
24 22 50       198 croak "Cannot open a pty" if not defined $ptyfd;
25              
26 22         444 my $pty = $class->SUPER::new_from_fd( $ptyfd, "r+" );
27 22 50       3229 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         194 $pty->autoflush(1);
33 22         981 bless $pty => $class;
34              
35 22         171 my $slave = IO::Tty->new_from_fd( $ttyfd, "r+" );
36 22 50       1179 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         112 $slave->autoflush(1);
41              
42 22         508 ${*$pty}{'io_pty_slave'} = $slave;
  22         114  
43 22         39 ${*$pty}{'io_pty_ttyname'} = $ttyname;
  22         77  
44 22         143 ${*$slave}{'io_tty_ttyname'} = $ttyname;
  22         96  
45              
46 22         94 return $pty;
47             }
48              
49             sub ttyname {
50 2 50   2 1 446 @_ == 1 or croak 'usage: $pty->ttyname();';
51 2         3 my $pty = shift;
52 2         2 ${*$pty}{'io_pty_ttyname'};
  2         6  
53             }
54              
55             sub close_slave {
56 5 50   5 1 5294 @_ == 1 or croak 'usage: $pty->close_slave();';
57              
58 5         245 my $master = shift;
59              
60 5 50       43 if ( exists ${*$master}{'io_pty_slave'} ) {
  5         263  
61 5         41 close ${*$master}{'io_pty_slave'};
  5         145  
62 5         22 delete ${*$master}{'io_pty_slave'};
  5         251  
63             }
64             }
65              
66             sub slave {
67 20 50   20 1 2989 @_ == 1 or croak 'usage: $pty->slave();';
68              
69 20         119 my $master = shift;
70              
71 20 100       31 if ( exists ${*$master}{'io_pty_slave'} ) {
  20         195  
72 18         37 return ${*$master}{'io_pty_slave'};
  18         98  
73             }
74              
75 2         3 my $tty = ${*$master}{'io_pty_ttyname'};
  2         3  
76              
77 2         38 my $slave_fd = IO::Tty::_open_tty($tty);
78 2 50       7 croak "Cannot open slave $tty: $!" if $slave_fd < 0;
79              
80 2         8 my $slave = IO::Tty->new_from_fd( $slave_fd, "r+" );
81 2 50       100 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         48 ${*$slave}{'io_tty_ttyname'} = $tty;
  2         4  
88 2         3 ${*$master}{'io_pty_slave'} = $slave;
  2         4  
89              
90 2         3 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, matching the slave() method.
120 0         0 my $ttyname = ${*$self}{'io_pty_ttyname'};
  0         0  
121 0         0 my $slave_fd = IO::Tty::_open_tty($ttyname);
122 0 0       0 croak "Cannot open slave $ttyname: $!" if $slave_fd < 0;
123 0         0 my $slv = IO::Tty->new_from_fd( $slave_fd, "r+" );
124 0 0       0 croak "Cannot create IO::Tty from fd $slave_fd: $!" if not $slv;
125 0         0 $slv->autoflush(1);
126              
127 0 0       0 if ( not exists ${*$self}{'io_pty_slave'} ) {
  0         0  
128 0         0 ${*$self}{'io_pty_slave'} = $slv;
  0         0  
129             }
130             else {
131 0         0 $slv->close;
132             }
133              
134             # Acquire a controlling terminal if this doesn't happen automatically
135 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
136 0 0       0 if ( defined TIOCSCTTY ) {
    0          
137 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TIOCSCTTY, 0 ) ) {
  0         0  
138 0         0 warn "warning: TIOCSCTTY failed, slave might not be set as controlling terminal: $!";
139             }
140             }
141             elsif ( defined TCSETCTTY ) {
142 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TCSETCTTY, 0 ) ) {
  0         0  
143 0         0 warn "warning: TCSETCTTY failed, slave might not be set as controlling terminal: $!";
144             }
145             }
146             else {
147 0         0 warn "warning: You have neither TIOCSCTTY nor TCSETCTTY on your system\n";
148 0         0 return 0;
149             }
150             }
151              
152 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
153 0         0 warn "Error: could not connect pty as controlling terminal!\n";
154 0         0 return undef;
155             }
156             else {
157 0         0 close \*DEVTTY;
158             }
159              
160 0         0 return 1;
161             }
162              
163             sub DESTROY {
164 22     22   6901276 my $self = shift;
165             # Only delete the internal reference; do not force-close the slave.
166             # Perl's refcounting will close the fd when no references remain.
167             # Force-closing here breaks consumers (e.g. IPC::Run) that hold
168             # their own reference to the slave obtained via $pty->slave().
169 22         36 delete ${*$self}{'io_pty_slave'};
  22         2256  
170             }
171              
172             *clone_winsize_from = \&IO::Tty::clone_winsize_from;
173             *get_winsize = \&IO::Tty::get_winsize;
174             *set_winsize = \&IO::Tty::set_winsize;
175             *set_raw = \&IO::Tty::set_raw;
176              
177             1;
178              
179             __END__