1*0Sstevel@tonic-gatepackage sigtrap; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gate=head1 NAME 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gatesigtrap - Perl pragma to enable simple signal handling 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gate=cut 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gateuse Carp; 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gate$VERSION = 1.02; 12*0Sstevel@tonic-gate$Verbose ||= 0; 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gatesub import { 15*0Sstevel@tonic-gate my $pkg = shift; 16*0Sstevel@tonic-gate my $handler = \&handler_traceback; 17*0Sstevel@tonic-gate my $saw_sig = 0; 18*0Sstevel@tonic-gate my $untrapped = 0; 19*0Sstevel@tonic-gate local $_; 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gate Arg_loop: 22*0Sstevel@tonic-gate while (@_) { 23*0Sstevel@tonic-gate $_ = shift; 24*0Sstevel@tonic-gate if (/^[A-Z][A-Z0-9]*$/) { 25*0Sstevel@tonic-gate $saw_sig++; 26*0Sstevel@tonic-gate unless ($untrapped and $SIG{$_} and $SIG{$_} ne 'DEFAULT') { 27*0Sstevel@tonic-gate print "Installing handler $handler for $_\n" if $Verbose; 28*0Sstevel@tonic-gate $SIG{$_} = $handler; 29*0Sstevel@tonic-gate } 30*0Sstevel@tonic-gate } 31*0Sstevel@tonic-gate elsif ($_ eq 'normal-signals') { 32*0Sstevel@tonic-gate unshift @_, grep(exists $SIG{$_}, qw(HUP INT PIPE TERM)); 33*0Sstevel@tonic-gate } 34*0Sstevel@tonic-gate elsif ($_ eq 'error-signals') { 35*0Sstevel@tonic-gate unshift @_, grep(exists $SIG{$_}, 36*0Sstevel@tonic-gate qw(ABRT BUS EMT FPE ILL QUIT SEGV SYS TRAP)); 37*0Sstevel@tonic-gate } 38*0Sstevel@tonic-gate elsif ($_ eq 'old-interface-signals') { 39*0Sstevel@tonic-gate unshift @_, 40*0Sstevel@tonic-gate grep(exists $SIG{$_}, 41*0Sstevel@tonic-gate qw(ABRT BUS EMT FPE ILL PIPE QUIT SEGV SYS TERM TRAP)); 42*0Sstevel@tonic-gate } 43*0Sstevel@tonic-gate elsif ($_ eq 'stack-trace') { 44*0Sstevel@tonic-gate $handler = \&handler_traceback; 45*0Sstevel@tonic-gate } 46*0Sstevel@tonic-gate elsif ($_ eq 'die') { 47*0Sstevel@tonic-gate $handler = \&handler_die; 48*0Sstevel@tonic-gate } 49*0Sstevel@tonic-gate elsif ($_ eq 'handler') { 50*0Sstevel@tonic-gate @_ or croak "No argument specified after 'handler'"; 51*0Sstevel@tonic-gate $handler = shift; 52*0Sstevel@tonic-gate unless (ref $handler or $handler eq 'IGNORE' 53*0Sstevel@tonic-gate or $handler eq 'DEFAULT') { 54*0Sstevel@tonic-gate require Symbol; 55*0Sstevel@tonic-gate $handler = Symbol::qualify($handler, (caller)[0]); 56*0Sstevel@tonic-gate } 57*0Sstevel@tonic-gate } 58*0Sstevel@tonic-gate elsif ($_ eq 'untrapped') { 59*0Sstevel@tonic-gate $untrapped = 1; 60*0Sstevel@tonic-gate } 61*0Sstevel@tonic-gate elsif ($_ eq 'any') { 62*0Sstevel@tonic-gate $untrapped = 0; 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate elsif ($_ =~ /^\d/) { 65*0Sstevel@tonic-gate $VERSION >= $_ or croak "sigtrap.pm version $_ required," 66*0Sstevel@tonic-gate . " but this is only version $VERSION"; 67*0Sstevel@tonic-gate } 68*0Sstevel@tonic-gate else { 69*0Sstevel@tonic-gate croak "Unrecognized argument $_"; 70*0Sstevel@tonic-gate } 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate unless ($saw_sig) { 73*0Sstevel@tonic-gate @_ = qw(old-interface-signals); 74*0Sstevel@tonic-gate goto Arg_loop; 75*0Sstevel@tonic-gate } 76*0Sstevel@tonic-gate} 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gatesub handler_die { 79*0Sstevel@tonic-gate croak "Caught a SIG$_[0]"; 80*0Sstevel@tonic-gate} 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gatesub handler_traceback { 83*0Sstevel@tonic-gate package DB; # To get subroutine args. 84*0Sstevel@tonic-gate $SIG{'ABRT'} = DEFAULT; 85*0Sstevel@tonic-gate kill 'ABRT', $$ if $panic++; 86*0Sstevel@tonic-gate syswrite(STDERR, 'Caught a SIG', 12); 87*0Sstevel@tonic-gate syswrite(STDERR, $_[0], length($_[0])); 88*0Sstevel@tonic-gate syswrite(STDERR, ' at ', 4); 89*0Sstevel@tonic-gate ($pack,$file,$line) = caller; 90*0Sstevel@tonic-gate syswrite(STDERR, $file, length($file)); 91*0Sstevel@tonic-gate syswrite(STDERR, ' line ', 6); 92*0Sstevel@tonic-gate syswrite(STDERR, $line, length($line)); 93*0Sstevel@tonic-gate syswrite(STDERR, "\n", 1); 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate # Now go for broke. 96*0Sstevel@tonic-gate for ($i = 1; ($p,$f,$l,$s,$h,$w,$e,$r) = caller($i); $i++) { 97*0Sstevel@tonic-gate @a = (); 98*0Sstevel@tonic-gate for $arg (@args) { 99*0Sstevel@tonic-gate $_ = "$arg"; 100*0Sstevel@tonic-gate s/([\'\\])/\\$1/g; 101*0Sstevel@tonic-gate s/([^\0]*)/'$1'/ 102*0Sstevel@tonic-gate unless /^(?: -?[\d.]+ | \*[\w:]* )$/x; 103*0Sstevel@tonic-gate s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg; 104*0Sstevel@tonic-gate s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg; 105*0Sstevel@tonic-gate push(@a, $_); 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate $w = $w ? '@ = ' : '$ = '; 108*0Sstevel@tonic-gate $a = $h ? '(' . join(', ', @a) . ')' : ''; 109*0Sstevel@tonic-gate $e =~ s/\n\s*\;\s*\Z// if $e; 110*0Sstevel@tonic-gate $e =~ s/[\\\']/\\$1/g if $e; 111*0Sstevel@tonic-gate if ($r) { 112*0Sstevel@tonic-gate $s = "require '$e'"; 113*0Sstevel@tonic-gate } elsif (defined $r) { 114*0Sstevel@tonic-gate $s = "eval '$e'"; 115*0Sstevel@tonic-gate } elsif ($s eq '(eval)') { 116*0Sstevel@tonic-gate $s = "eval {...}"; 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate $f = "file `$f'" unless $f eq '-e'; 119*0Sstevel@tonic-gate $mess = "$w$s$a called from $f line $l\n"; 120*0Sstevel@tonic-gate syswrite(STDERR, $mess, length($mess)); 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate kill 'ABRT', $$; 123*0Sstevel@tonic-gate} 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate1; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate__END__ 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate=head1 SYNOPSIS 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate use sigtrap; 132*0Sstevel@tonic-gate use sigtrap qw(stack-trace old-interface-signals); # equivalent 133*0Sstevel@tonic-gate use sigtrap qw(BUS SEGV PIPE ABRT); 134*0Sstevel@tonic-gate use sigtrap qw(die INT QUIT); 135*0Sstevel@tonic-gate use sigtrap qw(die normal-signals); 136*0Sstevel@tonic-gate use sigtrap qw(die untrapped normal-signals); 137*0Sstevel@tonic-gate use sigtrap qw(die untrapped normal-signals 138*0Sstevel@tonic-gate stack-trace any error-signals); 139*0Sstevel@tonic-gate use sigtrap 'handler' => \&my_handler, 'normal-signals'; 140*0Sstevel@tonic-gate use sigtrap qw(handler my_handler normal-signals 141*0Sstevel@tonic-gate stack-trace error-signals); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate=head1 DESCRIPTION 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gateThe B<sigtrap> pragma is a simple interface to installing signal 146*0Sstevel@tonic-gatehandlers. You can have it install one of two handlers supplied by 147*0Sstevel@tonic-gateB<sigtrap> itself (one which provides a Perl stack trace and one which 148*0Sstevel@tonic-gatesimply C<die()>s), or alternately you can supply your own handler for it 149*0Sstevel@tonic-gateto install. It can be told only to install a handler for signals which 150*0Sstevel@tonic-gateare either untrapped or ignored. It has a couple of lists of signals to 151*0Sstevel@tonic-gatetrap, plus you can supply your own list of signals. 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gateThe arguments passed to the C<use> statement which invokes B<sigtrap> 154*0Sstevel@tonic-gateare processed in order. When a signal name or the name of one of 155*0Sstevel@tonic-gateB<sigtrap>'s signal lists is encountered a handler is immediately 156*0Sstevel@tonic-gateinstalled, when an option is encountered it affects subsequently 157*0Sstevel@tonic-gateinstalled handlers. 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate=head1 OPTIONS 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate=head2 SIGNAL HANDLERS 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gateThese options affect which handler will be used for subsequently 164*0Sstevel@tonic-gateinstalled signals. 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate=over 4 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate=item B<stack-trace> 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gateThe handler used for subsequently installed signals outputs a Perl stack 171*0Sstevel@tonic-gatetrace to STDERR and then tries to dump core. This is the default signal 172*0Sstevel@tonic-gatehandler. 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate=item B<die> 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gateThe handler used for subsequently installed signals calls C<die> 177*0Sstevel@tonic-gate(actually C<croak>) with a message indicating which signal was caught. 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate=item B<handler> I<your-handler> 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gateI<your-handler> will be used as the handler for subsequently installed 182*0Sstevel@tonic-gatesignals. I<your-handler> can be any value which is valid as an 183*0Sstevel@tonic-gateassignment to an element of C<%SIG>. 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate=back 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate=head2 SIGNAL LISTS 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gateB<sigtrap> has a few built-in lists of signals to trap. They are: 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate=over 4 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate=item B<normal-signals> 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gateThese are the signals which a program might normally expect to encounter 196*0Sstevel@tonic-gateand which by default cause it to terminate. They are HUP, INT, PIPE and 197*0Sstevel@tonic-gateTERM. 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate=item B<error-signals> 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gateThese signals usually indicate a serious problem with the Perl 202*0Sstevel@tonic-gateinterpreter or with your script. They are ABRT, BUS, EMT, FPE, ILL, 203*0Sstevel@tonic-gateQUIT, SEGV, SYS and TRAP. 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate=item B<old-interface-signals> 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gateThese are the signals which were trapped by default by the old 208*0Sstevel@tonic-gateB<sigtrap> interface, they are ABRT, BUS, EMT, FPE, ILL, PIPE, QUIT, 209*0Sstevel@tonic-gateSEGV, SYS, TERM, and TRAP. If no signals or signals lists are passed to 210*0Sstevel@tonic-gateB<sigtrap>, this list is used. 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate=back 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gateFor each of these three lists, the collection of signals set to be 215*0Sstevel@tonic-gatetrapped is checked before trapping; if your architecture does not 216*0Sstevel@tonic-gateimplement a particular signal, it will not be trapped but rather 217*0Sstevel@tonic-gatesilently ignored. 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate=head2 OTHER 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate=over 4 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate=item B<untrapped> 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gateThis token tells B<sigtrap> to install handlers only for subsequently 226*0Sstevel@tonic-gatelisted signals which aren't already trapped or ignored. 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate=item B<any> 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gateThis token tells B<sigtrap> to install handlers for all subsequently 231*0Sstevel@tonic-gatelisted signals. This is the default behavior. 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate=item I<signal> 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gateAny argument which looks like a signal name (that is, 236*0Sstevel@tonic-gateC</^[A-Z][A-Z0-9]*$/>) indicates that B<sigtrap> should install a 237*0Sstevel@tonic-gatehandler for that name. 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate=item I<number> 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gateRequire that at least version I<number> of B<sigtrap> is being used. 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate=back 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate=head1 EXAMPLES 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gateProvide a stack trace for the old-interface-signals: 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate use sigtrap; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gateDitto: 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate use sigtrap qw(stack-trace old-interface-signals); 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gateProvide a stack trace on the 4 listed signals only: 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate use sigtrap qw(BUS SEGV PIPE ABRT); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gateDie on INT or QUIT: 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate use sigtrap qw(die INT QUIT); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gateDie on HUP, INT, PIPE or TERM: 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate use sigtrap qw(die normal-signals); 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gateDie on HUP, INT, PIPE or TERM, except don't change the behavior for 268*0Sstevel@tonic-gatesignals which are already trapped or ignored: 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate use sigtrap qw(die untrapped normal-signals); 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gateDie on receipt one of an of the B<normal-signals> which is currently 273*0Sstevel@tonic-gateB<untrapped>, provide a stack trace on receipt of B<any> of the 274*0Sstevel@tonic-gateB<error-signals>: 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate use sigtrap qw(die untrapped normal-signals 277*0Sstevel@tonic-gate stack-trace any error-signals); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gateInstall my_handler() as the handler for the B<normal-signals>: 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate use sigtrap 'handler', \&my_handler, 'normal-signals'; 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gateInstall my_handler() as the handler for the normal-signals, provide a 284*0Sstevel@tonic-gatePerl stack trace on receipt of one of the error-signals: 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate use sigtrap qw(handler my_handler normal-signals 287*0Sstevel@tonic-gate stack-trace error-signals); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate=cut 290