Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify Perl signal handler using the number, not the name

I want to specify a signal handler in Perl, but using the number, not the name. Is this possible in a succinct way? The lack of symmetry with kill particularly sticks out. For example, instead of

$SIG{USR2} = \&myhandler;

I'd like to say

$SIG{12} = \&myhandler;

The best I have at the moment is to "use Config" and poke around in $Config{sig_name}, based on the code in perldoc perlipc. This is verbose and seems needlessly complicated.

Rationale: I've wanted this in two cases recently.

1: I'm being started by a buggy parent process who incorrectly sets signals I care about to ignore, and I want to just reset everything to default. eg http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=679630 The goal would be something simple and brute force like:

foreach my $i (1..32) { $SIG{$i} = 'DEFAULT'; }

2: I'm writing a thin, as-invisible-as-possible wrapper script. If the program I'm wrapping exits with a signal, I want to exit with that same signal. However, I capture a few signals, so I need to clear my own signal handler to ensure i actually exit instead of entering my signal handler. My goal is to write something brief like this:

$ret = system("./other-program");
$SIG{$ret & 127} = 'DEFAULT';
kill $ret & 127, $$;
like image 550
Alan De Smet Avatar asked Jul 23 '12 21:07

Alan De Smet


2 Answers

First question:

use Config qw( %Config );

my @sig_name_by_num;
@sig_name_by_num[ split(' ', $Config{sig_num}) ] = split(' ', $Config{sig_name});

$SIG{$sig_name_by_num[12]} = \&handler;

Second question:

use Config qw( %Config );

$SIG{$_} = 'DEFAULT' for split ' ', $Config{sig_name};

-or-

$SIG{$_} = 'DEFAULT' for keys %SIG;

-or-

$_ = 'DEFAULT' for values %SIG;

Third question

use Config qw( %Config );

my @sig_name_by_num;
@sig_name_by_num[ split(' ', $Config{sig_num}) ] = split(' ', $Config{sig_name});

my $sig_num = $? & 0x7F;
$SIG{$sig_name_by_num[$sig_num]} = 'DEFAULT';
kill($sig_num => $$);
like image 131
ikegami Avatar answered Oct 16 '22 07:10

ikegami


If you just want to set all signals at once, you don't need to know their numbers:

$SIG{$_} = 'DEFAULT' for keys %SIG;

Using $Config{sig_name}/$Config{sig_num} is the only portable way to map signal numbers to names, but a quick and dirty way that works on many Unix-y systems is

$sig_name = qx(kill -l $sig_num);

($sig_name will then have a trailing newline, so in practice you'd want to do something like

chomp($sig_name = qx(kill -l $sig_num));
($sig_name) = qx(kill -l $sig_num) =~ /(\S+)/;

)

That's not necessarily any more concise than using %Config, though, unless you turned it into a function.

sub sig_no { chomp(my ($sig_no = qx(kill -l $_[0])); $sig_no }

$SIG{ sig_no($ret & 127) } = 'DEFAULT';
...
like image 40
mob Avatar answered Oct 16 '22 08:10

mob