xref: /openbsd-src/gnu/usr.bin/perl/t/io/pipe.t (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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        # POSIX-BC doesn't report failure when closing a broken pipe
151        # that has pending output.  Go figure.
152        skip "Won't report failure on broken pipe", 1
153          if $^O eq 'posix-bc';
154
155        local $SIG{PIPE} = 'IGNORE';
156        open NIL, qq{|$Perl -e "exit 0"} or die "open failed: $!";
157        sleep 5;
158        if (print NIL 'foo') {
159            # If print was allowed we had better get an error on close
160            ok( !close NIL,     'close error on broken pipe' );
161        }
162        else {
163            ok(close NIL,       'print failed on broken pipe');
164        }
165    }
166
167    {
168        # check that errno gets forced to 0 if the piped program exited
169        # non-zero
170        open NIL, qq{|$Perl -e "exit 23";} or die "fork failed: $!";
171        $! = 1;
172        ok(!close NIL,  'close failure on non-zero piped exit');
173        is($!, '',      '       errno');
174        isnt($?, 0,     '       status');
175
176	# Former skip block:
177        {
178            # check that status for the correct process is collected
179            my $zombie;
180            unless( $zombie = fork ) {
181                $NO_ENDING=1;
182                exit 37;
183            }
184            my $pipe = open *FH, "sleep 2;exit 13|" or die "Open: $!\n";
185            $SIG{ALRM} = sub { return };
186            alarm(1);
187            is( close FH, '',   'close failure for... umm, something' );
188            is( $?, 13*256,     '       status' );
189            is( $!, '',         '       errno');
190
191            my $wait = wait;
192            is( $?, 37*256,     'status correct after wait' );
193            is( $wait, $zombie, '       wait pid' );
194            is( $!, '',         '       errno');
195        }
196    }
197}
198
199# Test new semantics for missing command in piped open
200# 19990114 M-J. Dominus mjd@plover.com
201{ local *P;
202  no warnings 'pipe';
203  ok( !open(P, "|    "),        'missing command in piped open input' );
204  ok( !open(P, "     |"),       '                              output');
205}
206
207# check that status is unaffected by implicit close
208{
209    local(*NIL);
210    open NIL, qq{|$Perl -e "exit 23"} or die "fork failed: $!";
211    $? = 42;
212    # NIL implicitly closed here
213}
214is($?, 42,      'status unaffected by implicit close');
215$? = 0;
216
217# check that child is reaped if the piped program can't be executed
218SKIP: {
219  skip "/no_such_process exists", 1 if -e "/no_such_process";
220  open NIL, '/no_such_process |';
221  close NIL;
222
223  my $child = 0;
224  eval {
225    local $SIG{ALRM} = sub { die; };
226    alarm 2;
227    $child = wait;
228    alarm 0;
229  };
230
231  is($child, -1, 'child reaped if piped program cannot be executed');
232}
233