So I wrote a daemon, and I wrote an rc script to start it, and it works fine if I start it from the command line as:
but if I start it with
then many signals are blocked from reaching the daemon. SIGHUP in particular. Can anyone shed some light on what is happening here?
The problem can be demonstrated with to following code:
1) create /tmp/myd.in with some arbitrary data
2) start myd (works):
2a) start myd (broken):
3) monitor the myd output file:
4) and then start issuing SIGHUPs:
sample rc script (/usr/local/etc/rc.d/myd):
Sample daemon (/usr/local/sbin/myd):
Did I mention that the daemon is written in perl? I don't think it matters.
# /usr/local/etc/rc.d/myd start
but if I start it with
# env foo=bar /usr/local/etc/rc.d/myd start
then many signals are blocked from reaching the daemon. SIGHUP in particular. Can anyone shed some light on what is happening here?
The problem can be demonstrated with to following code:
1) create /tmp/myd.in with some arbitrary data
2) start myd (works):
# /usr/local/etc/rc.d/myd onestart
2a) start myd (broken):
# env foo=bar /usr/local/etc/rc.d/myd onestart
3) monitor the myd output file:
# tail -f /tmp/myd.out
4) and then start issuing SIGHUPs:
# /usr/local/etc/rc.d/myd onereload
sample rc script (/usr/local/etc/rc.d/myd):
Code:
#!/bin/sh
#
# PROVIDE: myd
# REQUIRE: syslogd
#
. /etc/rc.subr
name="myd"
rcvar=`set_rcvar`
pidfile="/var/run/${name}.pid"
command="/usr/local/sbin/${name}"
command_interpreter="/usr/bin/perl"
extra_commands="reload"
load_rc_config $name
run_rc_command "$1"
Sample daemon (/usr/local/sbin/myd):
Did I mention that the daemon is written in perl? I don't think it matters.
Code:
#!/usr/bin/perl
use strict;
use POSIX qw( setsid );
( my $me = $0 ) =~ s,.*/,,;
my %global = (
'infile' => "/tmp/$me.in",
'outfile' => "/tmp/$me.out",
'pidfile' => "/var/run/$me.pid",
'signal_exit' => 0,
'signal_reload' => 0,
);
my $slept = 0;
sub init() {
write_pid($$);
$SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&sig_catcher;
if ( -e $global{outfile} ) {
unlink $global{outfile};
}
my $data_in = read_conf();
write_conf( $data_in );
}
#
# detach
#
# Fork, detach and set up signal handling
#
sub detach {
my $pid = fork;
if ($pid) {
exit 0;
} elsif ( ! defined($pid) ) {
die "$me: Can't fork: $!";
}
setsid() or die "$me: Can't start new session.";
$SIG{PIPE} = 'IGNORE';
}
#
# sig_catcher
#
# catch the signals defined in detach() and do the right thing
# In this case the 'right thing' is to simply set a variable that
# gets examined in the main loop.
#
sub sig_catcher {
my $signame = shift;
if ( ( $signame eq 'INT' ) || ( $signame eq 'TERM' ) ){
$global{'signal_exit'} = 1;
} elsif ( $signame eq 'HUP' ) {
$global{'signal_reload'} = 1;
}
}
sub write_pid {
my $pid = shift;
open(FH, "> $global{pidfile}" ) or die;
print FH "$pid\n";
close(FH);
}
sub read_conf {
open(FH, "< $global{infile}" ) or die;
my @retval = <FH>;
close(FH);
return \@retval;
}
sub write_conf {
my $in_data = shift;
open(FH, ">> $global{outfile}" ) or die;
print FH "Slept $slept\nData = \n", @{$in_data};
close(FH);
}
#
# MAIN
#
detach();
init();
while(1) {
sleep 2;
$slept++;
} continue {
if ( $global{'signal_exit'} ){
unlink $global{pidfile};
exit 0;
}
if ( $global{'signal_reload'} ) {
my $data_in = read_conf();
write_conf( $data_in );
$global{'signal_reload'} = 0;
}
}