xref: /openbsd/gnu/usr.bin/perl/ext/POSIX/t/sigaction.t (revision eac174f2)
1#!./perl
2
3BEGIN{
4	# Don't do anything if POSIX is missing, or sigaction missing.
5	use Config;
6	eval 'use POSIX';
7	if($@ || $^O eq 'MSWin32' ||
8	   ($^O eq 'VMS' && !$Config{'d_sigaction'})) {
9		print "1..0\n";
10		exit 0;
11	}
12}
13
14use Test::More tests => 36;
15
16use strict;
17our ( $bad, $bad7, $ok10, $bad18, $ok );
18
19$^W=1;
20
21sub IGNORE {
22    ++$bad7;
23}
24
25sub DEFAULT {
26    ++$bad18;
27}
28
29sub foo {
30    ++$ok;
31}
32
33my $newaction=POSIX::SigAction->new('::foo', new POSIX::SigSet(SIGUSR1), 0);
34my $oldaction=POSIX::SigAction->new('::bar', new POSIX::SigSet(), 0);
35
36{
37	my $bad;
38	local($SIG{__WARN__})=sub { $bad=1; };
39	sigaction(SIGHUP, $newaction, $oldaction);
40	is($bad, undef, "no warnings");
41}
42
43like($oldaction->{HANDLER}, qr/\A(?:DEFAULT|IGNORE)\z/, '$oldaction->{HANDLER}');
44
45is($SIG{HUP}, '::foo');
46
47sigaction(SIGHUP, $newaction, $oldaction);
48is($oldaction->{HANDLER}, '::foo');
49
50ok($oldaction->{MASK}->ismember(SIGUSR1), "SIGUSR1 ismember MASK");
51
52SKIP: {
53    skip("sigaction() thinks different in $^O", 1)
54	if $^O eq 'linux' || $^O eq 'unicos';
55    is($oldaction->{FLAGS}, 0);
56}
57
58$newaction=POSIX::SigAction->new('IGNORE');
59sigaction(SIGHUP, $newaction);
60kill 'HUP', $$;
61is($bad, undef, "SIGHUP ignored");
62
63is($SIG{HUP}, 'IGNORE');
64sigaction(SIGHUP, POSIX::SigAction->new('DEFAULT'));
65is($SIG{HUP}, 'DEFAULT');
66
67$newaction=POSIX::SigAction->new(sub { ++$ok10; });
68sigaction(SIGHUP, $newaction);
69{
70	local($^W)=0;
71	kill 'HUP', $$;
72}
73is($ok10, 1, "SIGHUP handler called");
74
75is(ref($SIG{HUP}), 'CODE');
76
77sigaction(SIGHUP, POSIX::SigAction->new('::foo'));
78# Make sure the signal mask gets restored after sigaction croak()s.
79eval {
80	my $act=POSIX::SigAction->new('::foo');
81	delete $act->{HANDLER};
82	sigaction(SIGINT, $act);
83};
84kill 'HUP', $$;
85is($ok, 1, "signal mask gets restored after croak");
86
87undef $ok;
88# Make sure the signal mask gets restored after sigaction returns early.
89my $x=defined sigaction(SIGKILL, $newaction, $oldaction);
90kill 'HUP', $$;
91is($x, '', "signal mask gets restored after early return");
92is($ok, 1, "signal mask gets restored after early return");
93
94$SIG{HUP}=sub {};
95sigaction(SIGHUP, $newaction, $oldaction);
96is(ref($oldaction->{HANDLER}), 'CODE');
97
98eval {
99	sigaction(SIGHUP, undef, $oldaction);
100};
101is($@, '', "undef for new action");
102
103eval {
104	sigaction(SIGHUP, 0, $oldaction);
105};
106is($@, '', "zero for new action");
107
108eval {
109	sigaction(SIGHUP, bless({},'Class'), $oldaction);
110};
111like($@, qr/\Aaction is not of type POSIX::SigAction/,
112     'any object not good as new action');
113
114SKIP: {
115    skip("SIGCONT not trappable in $^O", 1)
116	if ($^O eq 'VMS');
117    $newaction=POSIX::SigAction->new(sub { ++$ok10; });
118    if (eval { SIGCONT; 1 }) {
119	sigaction(SIGCONT, POSIX::SigAction->new('DEFAULT'));
120	{
121	    local($^W)=0;
122	    kill 'CONT', $$;
123	}
124    }
125    is($bad18, undef, "SIGCONT trappable");
126}
127
128{
129    local $SIG{__WARN__} = sub { }; # Just suffer silently.
130
131    my $hup20;
132    my $hup21;
133
134    sub hup20 { $hup20++ }
135    sub hup21 { $hup21++ }
136
137    sigaction("FOOBAR", $newaction);
138    pass("no coredump, still alive");
139
140    $newaction = POSIX::SigAction->new("hup20");
141    sigaction("SIGHUP", $newaction);
142    kill "HUP", $$;
143    is($hup20, 1);
144
145    $newaction = POSIX::SigAction->new("hup21");
146    sigaction("HUP", $newaction);
147    kill "HUP", $$;
148    is ($hup21, 1);
149}
150
151# "safe" attribute.
152# for this one, use the accessor instead of the attribute
153
154# standard signal handling via %SIG is safe
155$SIG{HUP} = \&foo;
156$oldaction = POSIX::SigAction->new;
157sigaction(SIGHUP, undef, $oldaction);
158ok($oldaction->safe, "SIGHUP is safe");
159
160# SigAction handling is not safe ...
161sigaction(SIGHUP, POSIX::SigAction->new(\&foo));
162sigaction(SIGHUP, undef, $oldaction);
163ok(!$oldaction->safe, "SigAction not safe by default");
164
165# ... unless we say so!
166$newaction = POSIX::SigAction->new(\&foo);
167$newaction->safe(1);
168sigaction(SIGHUP, $newaction);
169sigaction(SIGHUP, undef, $oldaction);
170ok($oldaction->safe, "SigAction can be safe");
171
172# And safe signal delivery must work
173$ok = 0;
174kill 'HUP', $$;
175is($ok, 1, "safe signal delivery must work");
176
177SKIP: {
178    eval 'use POSIX qw(%SIGRT SIGRTMIN SIGRTMAX); scalar %SIGRT + SIGRTMIN() + SIGRTMAX()';
179    $@					# POSIX did not exort
180    || SIGRTMIN() < 0 || SIGRTMAX() < 0	# HP-UX 10.20 exports both as -1
181    || SIGRTMIN() > $Config{sig_count}	# AIX 4.3.3 exports bogus 888 and 999
182	and skip("no SIGRT signals", 4);
183    cmp_ok(SIGRTMAX(), '>', SIGRTMIN(), "SIGRTMAX > SIGRTMIN");
184    is(scalar %SIGRT, SIGRTMAX() - SIGRTMIN() + 1, "scalar SIGRT");
185    my $sigrtmin;
186    my $h = sub { $sigrtmin = 1 };
187    $SIGRT{SIGRTMIN} = $h;
188    is($SIGRT{SIGRTMIN}, $h, "handler set & get");
189    kill 'SIGRTMIN', $$;
190    is($sigrtmin, 1, "SIGRTMIN handler works");
191}
192
193SKIP: {
194    my %siginfo = (
195        signo => SIGHUP,
196        pid => $$,
197        uid => $<,
198    );
199    my %opt_val = ( code => 'SI_USER' );
200    my %always = map +($_ => 1), qw(signo code);
201    my %skip = ( code => { darwin => "not set to SI_USER for kill()" } );
202    $skip{pid}{$^O} = $skip{uid}{$^O} = "not set for kill()"
203        if (($^O.$Config{osvers}) =~ /^darwin[0-8]\./
204            ||
205            ($^O.$Config{osvers}) =~ /^openbsd[0-7]\./
206            ||
207            ($^O eq 'gnu')
208            ||
209            ($^O eq 'dragonfly'));
210    my $tests = keys %{{ %siginfo, %opt_val }};
211    eval 'use POSIX qw(SA_SIGINFO); SA_SIGINFO';
212    skip("no SA_SIGINFO", $tests) if $@;
213    skip("SA_SIGINFO is broken on AIX 4.2", $tests) if ($^O.$Config{osvers}) =~ m/^aix4\.2/;
214    skip("SA_SIGINFO is broken on os390", $tests) if ($^O.$Config{osvers}) =~ m/os390/;
215    eval "use POSIX qw($opt_val{$_}); \$siginfo{$_} = $opt_val{$_}"
216        for keys %opt_val;
217    sub hiphup {
218        for my $field (sort keys %{{ %siginfo, %opt_val }}) {
219            SKIP: {
220                skip("siginfo_t has no $field field", 1)
221                    unless %always{$field} or ($Config{"d_siginfo_si_$field"} || '') eq 'define';
222                skip("no constant defined for SA_SIGINFO $field value $opt_val{$field}", 1)
223                    unless defined $siginfo{$field};
224                skip("SA_SIGINFO $field value is wrong on $^O: $skip{$field}{$^O}", 1)
225                    if $skip{$field}{$^O};
226                is($_[1]->{$field}, $siginfo{$field}, "SA_SIGINFO got right $field")
227            }
228        }
229    }
230    my $act = POSIX::SigAction->new('hiphup', 0, SA_SIGINFO);
231    sigaction(SIGHUP, $act);
232    kill 'HUP', $$;
233}
234
235eval { sigaction(-999, "foo"); };
236like($@, qr/Negative signals/,
237    "Prevent negative signals instead of core dumping");
238
239# RT 77432 - assertion failure with POSIX::SigAction
240{
241  local *SIG = {};
242  ok(sigaction(SIGHUP, POSIX::SigAction->new),
243     "sigaction would crash/assert with a replaced %SIG");
244}
245