env blocks signals?

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:
# /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;
        }
}
 
Back
Top