File Coverage

blib/lib/IO/Pty.pm
Criterion Covered Total %
statement 67 103 65.0
branch 13 60 21.6
condition 1 2 50.0
subroutine 10 11 90.9
pod 5 5 100.0
total 96 181 53.0


line stmt bran cond sub pod time code
1             # Documentation at the __END__
2              
3             package IO::Pty;
4              
5 10     10   905376 use strict;
  10         15  
  10         303  
6 10     10   35 use warnings;
  10         15  
  10         476  
7 10     10   111 use Carp;
  10         11  
  10         604  
8 10     10   3838 use IO::Tty qw(TIOCSCTTY TCSETCTTY TIOCNOTTY);
  10         24  
  10         36  
9 10     10   57 use IO::File;
  10         17  
  10         10189  
10             require POSIX;
11              
12             our @ISA = qw(IO::Handle);
13             our $VERSION = '1.25'; # 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 2016477 my ($class) = $_[0] || "IO::Pty";
19 22 50       139 $class = ref($class) if ref($class);
20 22 50       167 @_ <= 1 or croak 'usage: new $class';
21              
22 22         3844 my ( $ptyfd, $ttyfd, $ttyname ) = pty_allocate();
23              
24 22 50       167 croak "Cannot open a pty" if not defined $ptyfd;
25              
26 22         486 my $pty = $class->SUPER::new_from_fd( $ptyfd, "r+" );
27 22 50       3655 croak "Cannot create a new $class from fd $ptyfd: $!" if not $pty;
28 22         235 $pty->autoflush(1);
29 22         1152 bless $pty => $class;
30              
31 22         161 my $slave = IO::Tty->new_from_fd( $ttyfd, "r+" );
32 22 50       1358 croak "Cannot create a new IO::Tty from fd $ttyfd: $!" if not $slave;
33 22         127 $slave->autoflush(1);
34              
35 22         557 ${*$pty}{'io_pty_slave'} = $slave;
  22         105  
36 22         38 ${*$pty}{'io_pty_ttyname'} = $ttyname;
  22         66  
37 22         74 ${*$slave}{'io_tty_ttyname'} = $ttyname;
  22         228  
38              
39 22         119 return $pty;
40             }
41              
42             sub ttyname {
43 2 50   2 1 442 @_ == 1 or croak 'usage: $pty->ttyname();';
44 2         2 my $pty = shift;
45 2         2 ${*$pty}{'io_pty_ttyname'};
  2         6  
46             }
47              
48             sub close_slave {
49 5 50   5 1 5453 @_ == 1 or croak 'usage: $pty->close_slave();';
50              
51 5         60 my $master = shift;
52              
53 5 50       50 if ( exists ${*$master}{'io_pty_slave'} ) {
  5         247  
54 5         52 close ${*$master}{'io_pty_slave'};
  5         93  
55 5         25 delete ${*$master}{'io_pty_slave'};
  5         326  
56             }
57             }
58              
59             sub slave {
60 20 50   20 1 3329 @_ == 1 or croak 'usage: $pty->slave();';
61              
62 20         54 my $master = shift;
63              
64 20 100       26 if ( exists ${*$master}{'io_pty_slave'} ) {
  20         129  
65 18         31 return ${*$master}{'io_pty_slave'};
  18         72  
66             }
67              
68 2         3 my $tty = ${*$master}{'io_pty_ttyname'};
  2         3  
69              
70 2         36 my $slave_fd = IO::Tty::_open_tty($tty);
71 2 50       5 croak "Cannot open slave $tty: $!" if $slave_fd < 0;
72              
73 2         6 my $slave = IO::Tty->new_from_fd( $slave_fd, "r+" );
74 2 50       98 croak "Cannot create IO::Tty from fd $slave_fd: $!" if not $slave;
75 2         5 $slave->autoflush(1);
76              
77 2         47 ${*$slave}{'io_tty_ttyname'} = $tty;
  2         5  
78 2         2 ${*$master}{'io_pty_slave'} = $slave;
  2         3  
79              
80 2         3 return $slave;
81             }
82              
83             sub make_slave_controlling_terminal {
84 0 0   0 1 0 @_ == 1 or croak 'usage: $pty->make_slave_controlling_terminal();';
85              
86 0         0 my $self = shift;
87 0         0 local (*DEVTTY);
88              
89             # loose controlling terminal explicitly
90 0 0       0 if ( defined TIOCNOTTY ) {
91 0 0       0 if ( open( \*DEVTTY, "/dev/tty" ) ) {
92 0         0 ioctl( \*DEVTTY, TIOCNOTTY, 0 );
93 0         0 close \*DEVTTY;
94             }
95             }
96              
97             # Create a new 'session', lose controlling terminal.
98 0 0       0 if ( POSIX::setsid() == -1 ) {
99 0 0       0 warn "setsid() failed, strange behavior may result: $!\r\n" if $^W;
100             }
101              
102 0 0       0 if ( open( \*DEVTTY, "/dev/tty" ) ) {
103 0 0       0 warn "Could not disconnect from controlling terminal?!\n" if $^W;
104 0         0 close \*DEVTTY;
105             }
106              
107             # now open slave, this should set it as controlling tty on some systems
108 0         0 my $ttyname = ${*$self}{'io_pty_ttyname'};
  0         0  
109 0         0 my $slv = IO::Tty->new;
110 0 0       0 $slv->open( $ttyname, O_RDWR )
111             or croak "Cannot open slave $ttyname: $!";
112              
113 0 0       0 if ( not exists ${*$self}{'io_pty_slave'} ) {
  0         0  
114 0         0 ${*$self}{'io_pty_slave'} = $slv;
  0         0  
115             }
116             else {
117 0         0 $slv->close;
118             }
119              
120             # Acquire a controlling terminal if this doesn't happen automatically
121 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
122 0 0       0 if ( defined TIOCSCTTY ) {
    0          
123 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TIOCSCTTY, 0 ) ) {
  0         0  
124 0 0       0 warn "warning: TIOCSCTTY failed, slave might not be set as controlling terminal: $!" if $^W;
125             }
126             }
127             elsif ( defined TCSETCTTY ) {
128 0 0       0 if ( not defined ioctl( ${*$self}{'io_pty_slave'}, TCSETCTTY, 0 ) ) {
  0         0  
129 0 0       0 warn "warning: TCSETCTTY failed, slave might not be set as controlling terminal: $!" if $^W;
130             }
131             }
132             else {
133 0 0       0 warn "warning: You have neither TIOCSCTTY nor TCSETCTTY on your system\n" if $^W;
134 0         0 return 0;
135             }
136             }
137              
138 0 0       0 if ( not open( \*DEVTTY, "/dev/tty" ) ) {
139 0         0 warn "Error: could not connect pty as controlling terminal!\n";
140 0         0 return undef;
141             }
142             else {
143 0         0 close \*DEVTTY;
144             }
145              
146 0         0 return 1;
147             }
148              
149             sub DESTROY {
150 22     22   6702003 my $self = shift;
151             # Only delete the internal reference; do not force-close the slave.
152             # Perl's refcounting will close the fd when no references remain.
153             # Force-closing here breaks consumers (e.g. IPC::Run) that hold
154             # their own reference to the slave obtained via $pty->slave().
155 22         48 delete ${*$self}{'io_pty_slave'};
  22         2688  
156             }
157              
158             *clone_winsize_from = \&IO::Tty::clone_winsize_from;
159             *get_winsize = \&IO::Tty::get_winsize;
160             *set_winsize = \&IO::Tty::set_winsize;
161             *set_raw = \&IO::Tty::set_raw;
162              
163             1;
164              
165             __END__