#!/usr/bin/perl use strict; use warnings; $|++; my $base = '/home/me/testing'; my $name = 'simpledaemon'; my $default_configfile = join '/', $base, $name . ".conf"; =head1 NAME B -- A daemon to ... =head1 SYNOPSIS simpledaemon [--start|--stop|--check] [--configfile ] Options: --help Display help --man Display man page --start Start the daemon (default) --stop Stop the daemon --check Check the daemon --configfile Specify alternate configuration file (default: simpledaemon.conf) =cut # # handle command line options # use Getopt::Long; use Pod::Usage; my %opt = ( help => 0, man => 0, configfile => $default_configfile, check => 0, stop => 0, start => 1, fork => 1, ); GetOptions(\%opt, 'help', 'man', 'configfile=s', 'check', 'stop', 'start!', 'fork!', ); # # handy dandy help and man options # pod2usage(-verbose => 1), exit if $opt{help}; pod2usage(-verbose => 2), exit if $opt{man}; # # load the config file # use Config::General; my $conf; # the object my %conf; # the handy hash # we eval this just to give pretty error messages... eval { $conf = Config::General->new( -ConfigFile => $opt{configfile}, -InterPolateVars => 1, ); }; if (local $_ = $@) { s/\n.*//; chomp; die "load config failed with: $_\n"; } # and voila! here's our conf %conf = $conf->getall; if (0) { # debugging use Data::Dumper; print Data::Dumper->Dump([\%conf],['conf']); } my $myname = $conf{Simpledaemon}{name}; # save some typing later on # # now we start the real work... handling --start, --stop, --check # use Proc::PID::File; my $pidfile; $pidfile = Proc::PID::File->new( # dir => $conf{Simpledaemon}{base}, # default: /var/run # name => 'simpledaemon', # default: progname (.pid g ets added) ); # only one of --check, --stop, --start will be performed. # handle --check if ($opt{check}) { if ($pidfile->alive) { print "$myname appears to be alive (pid ",$pidfile->read,").$/"; } else { print "$myname appears to be dead.$/"; } $pidfile = undef; exit 0; } # handle --stop if ($opt{stop}) { if ($pidfile->alive) { my $pid = $pidfile->read; kill TERM => $pid; sleep 2; if (kill 0, $pid) { print "$myname is hard to kill!$/"; exit 1; } else { print "$myname appears to be dead now.$/"; exit 0; } } else { print "$myname wasn't alive.$/"; exit 1; } } # handle --start sub logfailsafe { open(F, '>>', $conf{Simpledaemon}{logfailsafe}) and print(F @_) and close(F); die "@_"; } use Proc::Daemon; if ($opt{start}) { die "$myname already running!$/" if $pidfile->alive; # # fork if needed # we get a new pidfile here, Proc::Daemon::Init closes the open files (losing lo cks) # if ($opt{fork}) { $pidfile = undef; Proc::Daemon::Init; # become a daemon $pidfile = Proc::PID::File->new( # dir => '$conf{Simpledaemon}{base}', # default: /var/run # name => 'simpledaemon', # default: progname (.pid is added) ); } $pidfile->write; # # start our logging, try and fail gracefully # use Log::Log4perl qw(get_logger); eval { # Log::Log4perl::init(\$conf{logconfig}); Log::Log4perl::init_and_watch($conf{Simpledaemon}{logconfigfile} , 10); }; if (local $_ = $@) { s/ at .*//; chomp; logfailsafe("logging config failed with: $_\n"); } my $log = get_logger($conf{Simpledaemon}{logger}) or logfailsafe("get_logger failed!\n"); # # safeish death, pidfile is picky # $SIG{INT} = $SIG{TERM} = sub { $log->info("stopping"); $pidfile = undef; exit 0; }; $log->info("starting"); # # here's our loop # while (1) { no strict 'refs'; sleep 20; for my $i (qw/ debug info warn error fatal /) { $log->$i("log $i"); } } # # end of our loop # } # start __END__ =head1 DESCRIPTION This program will... =cut #### package MyDaemon; use base qw(SimpleDaemon); sub MainLoop { #do work here }