xref: /openbsd-src/gnu/usr.bin/perl/t/io/pipe.t (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1#!./perl
2
3BEGIN {
4    chdir 't' if -d 't';
5    @INC = '../lib';
6    require Config; import Config;
7    require './test.pl';
8
9    if (!$Config{'d_fork'}) {
10        skip_all("fork required to pipe");
11    }
12    else {
13        plan(tests => 24);
14    }
15}
16
17my $Perl = which_perl();
18
19
20$| = 1;
21
22open(PIPE, "|-") || exec $Perl, '-pe', 'tr/YX/ko/';
23
24printf PIPE "Xk %d - open |- || exec\n", curr_test();
25next_test();
26printf PIPE "oY %d -    again\n", curr_test();
27next_test();
28close PIPE;
29
30{
31    if (open(PIPE, "-|")) {
32	while(<PIPE>) {
33	    s/^not //;
34	    print;
35	}
36	close PIPE;        # avoid zombies
37    }
38    else {
39	printf STDOUT "not ok %d - open -|\n", curr_test();
40        next_test();
41        my $tnum = curr_test;
42        next_test();
43	exec $Perl, '-le', "print q{not ok $tnum -     again}";
44    }
45
46    # This has to be *outside* the fork
47    next_test() for 1..2;
48
49    my $raw = "abc\nrst\rxyz\r\nfoo\n";
50    if (open(PIPE, "-|")) {
51	$_ = join '', <PIPE>;
52	(my $raw1 = $_) =~ s/not ok \d+ - //;
53	my @r  = map ord, split //, $raw;
54	my @r1 = map ord, split //, $raw1;
55        if ($raw1 eq $raw) {
56	    s/^not (ok \d+ -) .*/$1 '@r1' passes through '-|'\n/s;
57	} else {
58	    s/^(not ok \d+ -) .*/$1 expect '@r', got '@r1'\n/s;
59	}
60	print;
61	close PIPE;        # avoid zombies
62    }
63    else {
64	printf STDOUT "not ok %d - $raw", curr_test();
65        exec $Perl, '-e0';	# Do not run END()...
66    }
67
68    # This has to be *outside* the fork
69    next_test();
70
71    if (open(PIPE, "|-")) {
72	printf PIPE "not ok %d - $raw", curr_test();
73	close PIPE;        # avoid zombies
74    }
75    else {
76	$_ = join '', <STDIN>;
77	(my $raw1 = $_) =~ s/not ok \d+ - //;
78	my @r  = map ord, split //, $raw;
79	my @r1 = map ord, split //, $raw1;
80        if ($raw1 eq $raw) {
81	    s/^not (ok \d+ -) .*/$1 '@r1' passes through '|-'\n/s;
82	} else {
83	    s/^(not ok \d+ -) .*/$1 expect '@r', got '@r1'\n/s;
84	}
85	print;
86        exec $Perl, '-e0';	# Do not run END()...
87    }
88
89    # This has to be *outside* the fork
90    next_test();
91
92    SKIP: {
93        skip "fork required", 2 unless $Config{d_fork};
94
95        pipe(READER,WRITER) || die "Can't open pipe";
96
97        if ($pid = fork) {
98            close WRITER;
99            while(<READER>) {
100                s/^not //;
101                y/A-Z/a-z/;
102                print;
103            }
104            close READER;     # avoid zombies
105        }
106        else {
107            die "Couldn't fork" unless defined $pid;
108            close READER;
109            printf WRITER "not ok %d - pipe & fork\n", curr_test;
110            next_test;
111
112            open(STDOUT,">&WRITER") || die "Can't dup WRITER to STDOUT";
113            close WRITER;
114
115            my $tnum = curr_test;
116            next_test;
117            exec $Perl, '-le', "print q{not ok $tnum -     with fh dup }";
118        }
119
120        # This has to be done *outside* the fork.
121        next_test() for 1..2;
122    }
123}
124wait;				# Collect from $pid
125
126pipe(READER,WRITER) || die "Can't open pipe";
127close READER;
128
129$SIG{'PIPE'} = 'broken_pipe';
130
131sub broken_pipe {
132    $SIG{'PIPE'} = 'IGNORE';       # loop preventer
133    printf "ok %d - SIGPIPE\n", curr_test;
134}
135
136printf WRITER "not ok %d - SIGPIPE\n", curr_test;
137close WRITER;
138sleep 1;
139next_test;
140pass();
141
142# VMS doesn't like spawning subprocesses that are still connected to
143# STDOUT.  Someone should modify these tests to work with VMS.
144
145SKIP: {
146    skip "doesn't like spawning subprocesses that are still connected", 10
147      if $^O eq 'VMS';
148
149    SKIP: {
150        # Sfio doesn't report failure when closing a broken pipe
151        # that has pending output.  Go figure.
152        # Nor does POSIX-BC.
153        skip "Won't report failure on broken pipe", 1
154          if $Config{d_sfio} || $^O eq 'posix-bc';
155
156        local $SIG{PIPE} = 'IGNORE';
157        open NIL, qq{|$Perl -e "exit 0"} or die "open failed: $!";
158        sleep 5;
159        if (print NIL 'foo') {
160            # If print was allowed we had better get an error on close
161            ok( !close NIL,     'close error on broken pipe' );
162        }
163        else {
164            ok(close NIL,       'print failed on broken pipe');
165        }
166    }
167
168    {
169        # check that errno gets forced to 0 if the piped program exited
170        # non-zero
171        open NIL, qq{|$Perl -e "exit 23";} or die "fork failed: $!";
172        $! = 1;
173        ok(!close NIL,  'close failure on non-zero piped exit');
174        is($!, '',      '       errno');
175        isnt($?, 0,     '       status');
176
177	# Former skip block:
178        {
179            # check that status for the correct process is collected
180            my $zombie;
181            unless( $zombie = fork ) {
182                $NO_ENDING=1;
183                exit 37;
184            }
185            my $pipe = open *FH, "sleep 2;exit 13|" or die "Open: $!\n";
186            $SIG{ALRM} = sub { return };
187            alarm(1);
188            is( close FH, '',   'close failure for... umm, something' );
189            is( $?, 13*256,     '       status' );
190            is( $!, '',         '       errno');
191
192            my $wait = wait;
193            is( $?, 37*256,     'status correct after wait' );
194            is( $wait, $zombie, '       wait pid' );
195            is( $!, '',         '       errno');
196        }
197    }
198}
199
200# Test new semantics for missing command in piped open
201# 19990114 M-J. Dominus mjd@plover.com
202{ local *P;
203  no warnings 'pipe';
204  ok( !open(P, "|    "),        'missing command in piped open input' );
205  ok( !open(P, "     |"),       '                              output');
206}
207
208# check that status is unaffected by implicit close
209{
210    local(*NIL);
211    open NIL, qq{|$Perl -e "exit 23"} or die "fork failed: $!";
212    $? = 42;
213    # NIL implicitly closed here
214}
215is($?, 42,      'status unaffected by implicit close');
216$? = 0;
217
218# check that child is reaped if the piped program can't be executed
219SKIP: {
220  skip "/no_such_process exists", 1 if -e "/no_such_process";
221  open NIL, '/no_such_process |';
222  close NIL;
223
224  my $child = 0;
225  eval {
226    local $SIG{ALRM} = sub { die; };
227    alarm 2;
228    $child = wait;
229    alarm 0;
230  };
231
232  is($child, -1, 'child reaped if piped program cannot be executed');
233}
234