summaryrefslogtreecommitdiff
path: root/FS/FS/Daemon.pm
blob: b58cde49f0716ad130507f05d3df8d51228710ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package FS::Daemon;

use vars qw( @ISA @EXPORT_OK );
use vars qw( $pid_dir $me $pid_file $sigint $sigterm $NOSIG $logfile );
use Exporter;
use Fcntl qw(:flock);
use POSIX qw(setsid);
use IO::File;
use File::Basename;
use File::Slurp qw(slurp);
use Date::Format;

#this is a simple refactoring of the stuff from freeside-queued, just to
#avoid duplicate code.  eventually this should use something from CPAN.

@ISA = qw(Exporter);
@EXPORT_OK = qw(
  daemonize1 drop_root daemonize2 myexit logfile sigint sigterm
);
%EXPORT_TAGS = ( 'all' => [ @EXPORT_OK ] );

$pid_dir = '/var/run';

$NOSIG = 0;
$PID_NEWSTYLE = 0;

sub daemonize1 {
  $me = shift;

  $pid_file = $pid_dir;
  if ( $PID_NEWSTYLE ) {
    $pid_file .= '/freeside';
    mkdir $pid_file unless -d $pid_file;
    chown $FS::UID::freeside_uid, -1, $pid_file;
  }
  $pid_file .= "/$me";
  $pid_file .= '.'.shift if scalar(@_);
  $pid_file .= '.pid';

  chdir "/" or die "Can't chdir to /: $!";
  open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
  defined(my $pid = fork) or die "Can't fork: $!";
  if ( $pid ) {
    print "$me started with pid $pid\n"; #logging to $log_file\n";
    exit unless $pid_file;
    my $pidfh = new IO::File ">$pid_file" or exit;
    chown $FS::UID::freeside_uid, -1, $pid_file;
    print $pidfh "$pid\n";
    exit;
  }

  #sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; $kids--; }
  #$SIG{CHLD} =  \&REAPER;
  $sigterm = 0;
  $sigint = 0;
  unless ( $NOSIG ) {
    $SIG{INT}  = sub { warn "SIGINT received; shutting down\n"; $sigint++;  };
    $SIG{TERM} = sub { warn "SIGTERM received; shutting down\n"; $sigterm++; };
  }
}

sub drop_root {
  my $freeside_gid = scalar(getgrnam('freeside'))
    or die "can't find freeside group\n";
  $) = $freeside_gid;
  $( = $freeside_gid;
  #if freebsd can't setuid(), presumably it can't setgid() either.  grr fleabsd
  ($(,$)) = ($),$();
  $) = $freeside_gid;
  
  $> = $FS::UID::freeside_uid;
  $< = $FS::UID::freeside_uid;
  #freebsd is sofa king broken, won't setuid()
  ($<,$>) = ($>,$<);
  $> = $FS::UID::freeside_uid;
}

sub daemonize2 {
  open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";
  setsid                    or die "Can't start a new session: $!";
  open STDERR, '>&STDOUT'   or die "Can't dup stdout: $!";

  $SIG{__DIE__} = \&_die;
  $SIG{__WARN__} = \&_logmsg;

  warn "$me starting\n";
}

sub sigint  { $sigint; }
sub sigterm { $sigterm; }

sub logfile { $logfile = shift; } #_logmsg('test'); }

sub myexit {
  chomp( my $pid = slurp($pid_file) );
  unlink $pid_file if -e $pid_file && $$ == $pid;
  exit;  
}

sub _die {
  die @_ if $^S; # $^S = 1 during an eval(), don't break exception handling
  my $msg = shift;

  chomp( my $pid = slurp($pid_file) );
  unlink $pid_file if -e $pid_file && $$ == $pid;

  _logmsg($msg);
}

sub _logmsg {
  chomp( my $msg = shift );
  my $log = new IO::File ">>$logfile";
  flock($log, LOCK_EX);
  seek($log, 0, 2);
  print $log "[". time2str("%a %b %e %T %Y",time). "] [$$] $msg\n";
  flock($log, LOCK_UN);
  close $log;
}

1;