| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package IO::Pty::Easy; |
|
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:DOY'; |
|
3
|
|
|
|
|
|
|
$IO::Pty::Easy::VERSION = '0.10'; |
|
4
|
4
|
|
|
4
|
|
51078
|
use warnings; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
113
|
|
|
5
|
4
|
|
|
4
|
|
13
|
use strict; |
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
66
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Easy interface to IO::Pty |
|
7
|
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
9
|
use Carp; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
253
|
|
|
9
|
4
|
|
|
4
|
|
1650
|
use POSIX (); |
|
|
4
|
|
|
|
|
22653
|
|
|
|
4
|
|
|
|
|
131
|
|
|
10
|
4
|
|
|
4
|
|
29
|
use Scalar::Util qw(weaken); |
|
|
4
|
|
|
|
|
4
|
|
|
|
4
|
|
|
|
|
407
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
4
|
|
|
4
|
|
25
|
use base 'IO::Pty'; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
2254
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub new { |
|
17
|
5
|
|
|
5
|
1
|
62
|
my $class = shift; |
|
18
|
5
|
|
|
|
|
12
|
my %args = @_; |
|
19
|
|
|
|
|
|
|
|
|
20
|
5
|
|
|
|
|
8
|
my $handle_pty_size = 1; |
|
21
|
|
|
|
|
|
|
$handle_pty_size = delete $args{handle_pty_size} |
|
22
|
5
|
50
|
|
|
|
17
|
if exists $args{handle_pty_size}; |
|
23
|
5
|
50
|
|
|
|
102
|
$handle_pty_size = 0 unless POSIX::isatty(*STDIN); |
|
24
|
5
|
|
|
|
|
763
|
my $def_max_read_chars = 8192; |
|
25
|
|
|
|
|
|
|
$def_max_read_chars = delete $args{def_max_read_chars} |
|
26
|
5
|
50
|
|
|
|
23
|
if exists $args{def_max_read_chars}; |
|
27
|
5
|
|
|
|
|
6
|
my $raw = 1; |
|
28
|
|
|
|
|
|
|
$raw = delete $args{raw} |
|
29
|
5
|
50
|
|
|
|
14
|
if exists $args{raw}; |
|
30
|
|
|
|
|
|
|
|
|
31
|
5
|
|
|
|
|
47
|
my $self = $class->SUPER::new(%args); |
|
32
|
5
|
|
|
|
|
3462
|
bless $self, $class; |
|
33
|
5
|
|
|
|
|
19
|
$self->handle_pty_size($handle_pty_size); |
|
34
|
5
|
|
|
|
|
14
|
$self->def_max_read_chars($def_max_read_chars); |
|
35
|
5
|
|
|
|
|
5
|
${*{$self}}{io_pty_easy_raw} = $raw; |
|
|
5
|
|
|
|
|
5
|
|
|
|
5
|
|
|
|
|
11
|
|
|
36
|
5
|
|
|
|
|
5
|
${*{$self}}{io_pty_easy_final_output} = ''; |
|
|
5
|
|
|
|
|
5
|
|
|
|
5
|
|
|
|
|
15
|
|
|
37
|
5
|
|
|
|
|
5
|
${*{$self}}{io_pty_easy_did_handle_pty_size} = 0; |
|
|
5
|
|
|
|
|
51
|
|
|
|
5
|
|
|
|
|
12
|
|
|
38
|
|
|
|
|
|
|
|
|
39
|
5
|
|
|
|
|
15
|
return $self; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub spawn { |
|
44
|
6
|
|
|
6
|
1
|
18
|
my $self = shift; |
|
45
|
6
|
|
|
|
|
36
|
my $slave = $self->slave; |
|
46
|
|
|
|
|
|
|
|
|
47
|
6
|
50
|
|
|
|
409
|
croak "Attempt to spawn a subprocess when one is already running" |
|
48
|
|
|
|
|
|
|
if $self->is_active; |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# set up a pipe to use for keeping track of the child process during exec |
|
51
|
6
|
|
|
|
|
9
|
my ($readp, $writep); |
|
52
|
6
|
50
|
|
|
|
123
|
unless (pipe($readp, $writep)) { |
|
53
|
0
|
|
|
|
|
0
|
croak "Failed to create a pipe"; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
6
|
|
|
|
|
22
|
$writep->autoflush(1); |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
# fork a child process |
|
58
|
|
|
|
|
|
|
# if the exec fails, signal the parent by sending the errno across the pipe |
|
59
|
|
|
|
|
|
|
# if the exec succeeds, perl will close the pipe, and the sysread will |
|
60
|
|
|
|
|
|
|
# return due to EOF |
|
61
|
6
|
|
|
|
|
4345
|
${*{$self}}{io_pty_easy_pid} = fork; |
|
|
6
|
|
|
|
|
62
|
|
|
|
6
|
|
|
|
|
257
|
|
|
62
|
6
|
100
|
|
|
|
113
|
unless ($self->pid) { |
|
63
|
3
|
|
|
|
|
85
|
close $readp; |
|
64
|
3
|
|
|
|
|
215
|
$self->make_slave_controlling_terminal; |
|
65
|
3
|
|
|
|
|
1579
|
close $self; |
|
66
|
3
|
50
|
|
|
|
34
|
$slave->clone_winsize_from(\*STDIN) if $self->handle_pty_size; |
|
67
|
3
|
50
|
|
|
|
13
|
$slave->set_raw if ${*{$self}}{io_pty_easy_raw}; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
98
|
|
|
68
|
|
|
|
|
|
|
# reopen the standard file descriptors in the child to point to the |
|
69
|
|
|
|
|
|
|
# pty rather than wherever they have been pointing during the script's |
|
70
|
|
|
|
|
|
|
# execution |
|
71
|
3
|
50
|
|
|
|
817
|
open(STDIN, '<&', $slave->fileno) |
|
72
|
|
|
|
|
|
|
or carp "Couldn't reopen STDIN for reading"; |
|
73
|
3
|
50
|
|
|
|
163
|
open(STDOUT, '>&', $slave->fileno) |
|
74
|
|
|
|
|
|
|
or carp "Couldn't reopen STDOUT for writing"; |
|
75
|
3
|
50
|
|
|
|
58
|
open(STDERR, '>&', $slave->fileno) |
|
76
|
|
|
|
|
|
|
or carp "Couldn't reopen STDERR for writing"; |
|
77
|
3
|
|
|
|
|
48
|
close $slave; |
|
78
|
3
|
|
|
|
|
9
|
{ exec(@_) }; |
|
|
3
|
|
|
|
|
0
|
|
|
79
|
0
|
|
|
|
|
0
|
print $writep $! + 0; |
|
80
|
0
|
|
|
|
|
0
|
carp "Cannot exec(@_): $!"; |
|
81
|
0
|
|
|
|
|
0
|
exit 1; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
3
|
|
|
|
|
50
|
close $writep; |
|
85
|
3
|
|
|
|
|
114
|
$self->close_slave; |
|
86
|
|
|
|
|
|
|
# this sysread will block until either we get an EOF from the other end of |
|
87
|
|
|
|
|
|
|
# the pipe being closed due to the exec, or until the child process sends |
|
88
|
|
|
|
|
|
|
# us the errno of the exec call after it fails |
|
89
|
3
|
|
|
|
|
48
|
my $errno; |
|
90
|
3
|
|
|
|
|
1895991
|
my $read_bytes = sysread($readp, $errno, 256); |
|
91
|
3
|
50
|
|
|
|
35
|
unless (defined $read_bytes) { |
|
92
|
|
|
|
|
|
|
# XXX: should alarm here and follow up with SIGKILL if the process |
|
93
|
|
|
|
|
|
|
# refuses to die |
|
94
|
0
|
|
|
|
|
0
|
kill TERM => $self->pid; |
|
95
|
0
|
|
|
|
|
0
|
close $readp; |
|
96
|
0
|
|
|
|
|
0
|
$self->_wait_for_inactive; |
|
97
|
0
|
|
|
|
|
0
|
croak "Cannot sync with child: $!"; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
3
|
|
|
|
|
61
|
close $readp; |
|
100
|
3
|
50
|
|
|
|
14
|
if ($read_bytes > 0) { |
|
101
|
0
|
|
|
|
|
0
|
$errno = $errno + 0; |
|
102
|
0
|
|
|
|
|
0
|
$self->_wait_for_inactive; |
|
103
|
0
|
|
|
|
|
0
|
croak "Cannot exec(@_): $errno"; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
|
|
|
|
|
|
|
|
106
|
3
|
50
|
|
|
|
28
|
if ($self->handle_pty_size) { |
|
107
|
0
|
|
|
|
|
0
|
my $weakself = weaken($self); |
|
108
|
|
|
|
|
|
|
$SIG{WINCH} = sub { |
|
109
|
0
|
0
|
|
0
|
|
0
|
return unless $weakself; |
|
110
|
0
|
|
|
|
|
0
|
$weakself->slave->clone_winsize_from(\*STDIN); |
|
111
|
0
|
0
|
|
|
|
0
|
kill WINCH => $weakself->pid if $weakself->is_active; |
|
112
|
0
|
|
|
|
|
0
|
}; |
|
113
|
0
|
|
|
|
|
0
|
${*{$self}}{io_pty_easy_did_handle_pty_size} = 1; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub read { |
|
119
|
4
|
|
|
4
|
1
|
20
|
my $self = shift; |
|
120
|
4
|
|
|
|
|
10
|
my ($timeout, $max_chars) = @_; |
|
121
|
4
|
|
33
|
|
|
30
|
$max_chars ||= $self->def_max_read_chars; |
|
122
|
|
|
|
|
|
|
|
|
123
|
4
|
|
|
|
|
8
|
my $rin = ''; |
|
124
|
4
|
|
|
|
|
14
|
vec($rin, fileno($self), 1) = 1; |
|
125
|
4
|
|
|
|
|
204758
|
my $nfound = select($rin, undef, undef, $timeout); |
|
126
|
4
|
|
|
|
|
14
|
my $buf; |
|
127
|
4
|
100
|
|
|
|
20
|
if ($nfound > 0) { |
|
128
|
2
|
|
|
|
|
24
|
my $nchars = sysread($self, $buf, $max_chars); |
|
129
|
2
|
50
|
33
|
|
|
18
|
$buf = '' if defined($nchars) && $nchars == 0; |
|
130
|
|
|
|
|
|
|
} |
|
131
|
4
|
50
|
|
|
|
6
|
if (length(${*{$self}}{io_pty_easy_final_output}) > 0) { |
|
|
4
|
|
|
|
|
6
|
|
|
|
4
|
|
|
|
|
46
|
|
|
132
|
4
|
|
|
4
|
|
54598
|
no warnings 'uninitialized'; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
2167
|
|
|
133
|
0
|
|
|
|
|
0
|
$buf = ${*{$self}}{io_pty_easy_final_output} . $buf; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
134
|
0
|
|
|
|
|
0
|
${*{$self}}{io_pty_easy_final_output} = ''; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
135
|
|
|
|
|
|
|
} |
|
136
|
4
|
|
|
|
|
76
|
return $buf; |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub write { |
|
141
|
4
|
|
|
4
|
1
|
38
|
my $self = shift; |
|
142
|
4
|
|
|
|
|
12
|
my ($text, $timeout) = @_; |
|
143
|
|
|
|
|
|
|
|
|
144
|
4
|
|
|
|
|
8
|
my $win = ''; |
|
145
|
4
|
|
|
|
|
31
|
vec($win, fileno($self), 1) = 1; |
|
146
|
4
|
|
|
|
|
100210
|
my $nfound = select(undef, $win, undef, $timeout); |
|
147
|
4
|
|
|
|
|
7
|
my $nchars; |
|
148
|
4
|
100
|
|
|
|
16
|
if ($nfound > 0) { |
|
149
|
3
|
|
|
|
|
999410
|
$nchars = syswrite($self, $text); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
4
|
|
|
|
|
61
|
return $nchars; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub is_active { |
|
156
|
23
|
|
|
23
|
1
|
27
|
my $self = shift; |
|
157
|
|
|
|
|
|
|
|
|
158
|
23
|
100
|
|
|
|
48
|
return 0 unless defined $self->pid; |
|
159
|
|
|
|
|
|
|
|
|
160
|
9
|
50
|
|
|
|
34
|
if (defined(my $fd = fileno($self))) { |
|
161
|
|
|
|
|
|
|
# XXX FreeBSD 7.0 will not allow a session leader to exit until the |
|
162
|
|
|
|
|
|
|
# kernel tty output buffer is empty. Make it so. |
|
163
|
9
|
|
|
|
|
15
|
my $rin = ''; |
|
164
|
9
|
|
|
|
|
32
|
vec($rin, $fd, 1) = 1; |
|
165
|
9
|
|
|
|
|
54
|
my $nfound = select($rin, undef, undef, 0); |
|
166
|
9
|
100
|
|
|
|
25
|
if ($nfound > 0) { |
|
167
|
3
|
|
|
|
|
4
|
sysread($self, ${*{$self}}{io_pty_easy_final_output}, |
|
|
3
|
|
|
|
|
19
|
|
|
168
|
|
|
|
|
|
|
$self->def_max_read_chars, |
|
169
|
3
|
|
|
|
|
8
|
length ${*{$self}}{io_pty_easy_final_output}); |
|
|
3
|
|
|
|
|
5
|
|
|
|
3
|
|
|
|
|
42
|
|
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
9
|
|
|
|
|
20
|
my $active = kill 0 => $self->pid; |
|
174
|
9
|
50
|
|
|
|
22
|
if ($active) { |
|
175
|
9
|
|
|
|
|
19
|
my $pid = waitpid($self->pid, POSIX::WNOHANG()); |
|
176
|
9
|
100
|
|
|
|
15
|
$active = 0 if $pid == $self->pid; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
9
|
100
|
|
|
|
22
|
if (!$active) { |
|
179
|
|
|
|
|
|
|
$SIG{WINCH} = 'DEFAULT' |
|
180
|
3
|
50
|
|
|
|
3
|
if ${*{$self}}{io_pty_easy_did_handle_pty_size}; |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
11
|
|
|
181
|
3
|
|
|
|
|
4
|
${*{$self}}{io_pty_easy_did_handle_pty_size} = 0; |
|
|
3
|
|
|
|
|
4
|
|
|
|
3
|
|
|
|
|
5
|
|
|
182
|
3
|
|
|
|
|
5
|
delete ${*{$self}}{io_pty_easy_pid}; |
|
|
3
|
|
|
|
|
3
|
|
|
|
3
|
|
|
|
|
7
|
|
|
183
|
|
|
|
|
|
|
} |
|
184
|
9
|
|
|
|
|
30337
|
return $active; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub kill { |
|
189
|
7
|
|
|
7
|
1
|
12
|
my $self = shift; |
|
190
|
7
|
|
|
|
|
11
|
my ($sig, $non_blocking) = @_; |
|
191
|
7
|
50
|
|
|
|
27
|
$sig = "TERM" unless defined $sig; |
|
192
|
|
|
|
|
|
|
|
|
193
|
7
|
|
|
|
|
6
|
my $kills; |
|
194
|
7
|
100
|
|
|
|
22
|
$kills = kill $sig => $self->pid if $self->is_active; |
|
195
|
7
|
50
|
|
|
|
40
|
$self->_wait_for_inactive unless $non_blocking; |
|
196
|
|
|
|
|
|
|
|
|
197
|
7
|
|
|
|
|
82
|
return $kills; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub close { |
|
202
|
4
|
|
|
4
|
1
|
9
|
my $self = shift; |
|
203
|
|
|
|
|
|
|
|
|
204
|
4
|
|
|
|
|
102
|
close $self; |
|
205
|
4
|
|
|
|
|
16
|
$self->kill; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub handle_pty_size { |
|
210
|
11
|
|
|
11
|
1
|
22
|
my $self = shift; |
|
211
|
11
|
100
|
|
|
|
35
|
${*{$self}}{io_pty_easy_handle_pty_size} = $_[0] if @_; |
|
|
5
|
|
|
|
|
5
|
|
|
|
5
|
|
|
|
|
11
|
|
|
212
|
11
|
|
|
|
|
17
|
${*{$self}}{io_pty_easy_handle_pty_size}; |
|
|
11
|
|
|
|
|
8
|
|
|
|
11
|
|
|
|
|
132
|
|
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub def_max_read_chars { |
|
217
|
12
|
|
|
12
|
1
|
16
|
my $self = shift; |
|
218
|
12
|
100
|
|
|
|
31
|
${*{$self}}{io_pty_easy_def_max_read_chars} = $_[0] if @_; |
|
|
5
|
|
|
|
|
5
|
|
|
|
5
|
|
|
|
|
9
|
|
|
219
|
12
|
|
|
|
|
16
|
${*{$self}}{io_pty_easy_def_max_read_chars}; |
|
|
12
|
|
|
|
|
9
|
|
|
|
12
|
|
|
|
|
35
|
|
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub pid { |
|
224
|
59
|
|
|
59
|
1
|
57
|
my $self = shift; |
|
225
|
59
|
|
|
|
|
41
|
${*{$self}}{io_pty_easy_pid}; |
|
|
59
|
|
|
|
|
45
|
|
|
|
59
|
|
|
|
|
384
|
|
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub _wait_for_inactive { |
|
229
|
7
|
|
|
7
|
|
11
|
my $self = shift; |
|
230
|
|
|
|
|
|
|
|
|
231
|
7
|
|
|
|
|
13
|
select(undef, undef, undef, 0.01) while $self->is_active; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
sub DESTROY { |
|
235
|
2
|
|
|
2
|
|
397
|
my $self = shift; |
|
236
|
2
|
|
|
|
|
3
|
local $@; |
|
237
|
2
|
|
|
|
|
7
|
local $?; |
|
238
|
2
|
|
|
|
|
6
|
$self->close; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
1; |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
__END__ |