Created
May 11, 2011 18:12
-
-
Save yinyin/966982 to your computer and use it in GitHub Desktop.
An utility which runs program as daemon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use POSIX; | |
our $PID = '/tmp/pid.txt'; | |
our $WORKDIR = '/tmp'; | |
our $TRMLOG = '/dev/null'; # '/tmp/terminal-log.txt'; | |
our @DAEMON_CMD = (); | |
our $VERBOSE = 0; | |
our $RUNTIME_STOP_SIGNAL = 0; | |
my $operation_mode = 'start'; | |
eval { | |
my $readopt = 1; | |
OPTLOOP: for(my $i = 0; $i <= $#ARGV; $i++) { | |
my $opt = $ARGV[$i]; | |
my $processed = 0; | |
if(0 != $readopt) | |
{ | |
$processed = 1; | |
if($opt =~ /^--pid=(.+)$/) | |
{ $PID = $1; $PID =~ s/\s+$//; } | |
elsif($opt =~/^--(working-dir|wd)=(.+)$/) | |
{ $WORKDIR = $2; $WORKDIR =~ s/\s+$//; } | |
elsif($opt =~/^--(log|terminal-log)=(.+)$/) | |
{ $TRMLOG = $2; $TRMLOG =~ s/\s+$//; } | |
elsif( ($opt eq '-v') or ($opt eq '--verbose') ) | |
{ $VERBOSE = 1; } | |
elsif($opt eq '--') | |
{ $readopt = 0; } | |
elsif($opt eq 'start') | |
{ $operation_mode = 'start'; } | |
elsif($opt eq 'stop') | |
{ $operation_mode = 'stop'; } | |
elsif( ($opt eq 'check') or ($opt eq 'status') ) | |
{ $operation_mode = 'check'; } | |
elsif($opt eq 'startstart') | |
{ $operation_mode = 'startstart'; } | |
else | |
{ $processed = 0; } | |
} | |
if(0 == $processed) | |
{ push @DAEMON_CMD, $opt; } | |
} | |
}; | |
if(0 != $VERBOSE) | |
{ | |
print "PID-file = ${PID}\n"; | |
print "Working-directory = ${WORKDIR}\n"; | |
print "Terminal-log = ${TRMLOG}\n"; | |
print "Command = @{DAEMON_CMD}\n"; | |
print "Operation-mode = ${operation_mode}\n"; | |
} | |
sub my_fork # {{{ | |
{ | |
my $child_pid; | |
FORKLOOP: { | |
if(defined($child_pid = fork)) | |
{ return $child_pid; } | |
elsif($! =~ /No more process/) | |
{ | |
sleep 10; | |
redo FORKLOOP; | |
} | |
else | |
{ | |
print "can not fork $!\n"; | |
exit; | |
} | |
} | |
} # }}} | |
sub have_process # {{{ | |
{ | |
my $line; | |
my $result; | |
my $parget; | |
$parget = int(shift); | |
# print "parget: $parget\n"; | |
open(PSFH, '-|', '/bin/ps x -o pid,command') or die 'can not get process list'; | |
$result = undef; | |
while($line = <PSFH>) { | |
# print $line; | |
$line =~ s/^\s+//; | |
$line =~ s/\s+$//; | |
if( $line =~ /^([0-9]+)\s+/ ) | |
{ | |
my $v = int($1); | |
if($v == $parget) | |
{ $result = $line; } | |
# print "> $line\n"; | |
} | |
} | |
close PSFH; | |
return $result; | |
} # }}} | |
sub signalhandler_GOSTOP | |
{ | |
$RUNTIME_STOP_SIGNAL = 1; | |
} | |
# {{{ check ps to see if any running bot | |
my $prev_pid; | |
my $prev_cmd; | |
my $curr_cmd; | |
if(open(PIDF, '<', $PID)) | |
{ | |
$prev_pid = <PIDF>; $prev_pid =~ s/^\s+//; $prev_pid =~ s/\s+$//; $prev_pid = int($prev_pid); | |
$prev_cmd = <PIDF>; $prev_cmd =~ s/^\s+//; $prev_cmd =~ s/\s+$//; | |
close PIDF; | |
} | |
else | |
{ | |
$prev_pid = 0; | |
$prev_cmd = 'NA'; | |
} | |
$curr_cmd = have_process($prev_pid); | |
if( (undef ne $curr_cmd) and ($prev_cmd eq $curr_cmd) ) | |
{ | |
if(0 != $VERBOSE) | |
{ print "Daemon still running.\n"; } | |
if('check' eq $operation_mode) | |
{ exit 0; } | |
if('stop' eq $operation_mode) | |
{ | |
kill SIGTERM, $prev_pid; | |
exit 0; | |
} | |
exit 10; | |
} | |
# }}} | |
if( ('check' eq $operation_mode) or ('stop' eq $operation_mode) ) | |
{ | |
if(0 != $VERBOSE) | |
{ print "Daemon not running.\n"; } | |
exit 1; | |
} | |
# {{{ 1st fork, detach from user command | |
my $now_pid; | |
if($now_pid = my_fork) | |
{ | |
exit 0; | |
} | |
# }}} | |
# {{{ set session id, detach from control console | |
POSIX::setsid() or die 'Can not detach from controll console'; | |
# }}} | |
# {{{ 2nd fork, release from control console | |
$SIG{'HUP'} = 'IGNORE'; | |
if($now_pid = my_fork) | |
{ | |
sleep 6; | |
open(PIDF, "> $PID") or die 'can not open pid.txt for write'; | |
my $now_cmd = have_process($now_pid); | |
# print "writing pid.txt ($now_pid, $now_cmd)\n"; | |
print PIDF "$now_pid\n$now_cmd\n\n"; | |
close PIDF; | |
exit 0; | |
} | |
# }}} | |
chdir $WORKDIR; | |
my $openmax; | |
$openmax = POSIX::sysconf( &POSIX::_SC_OPEN_MAX ); | |
$openmax = (!defined($openmax) || $openmax < 0) ? 64 : $openmax; | |
foreach my $i (0 .. $openmax) { POSIX::close($i); } | |
open(STDIN, '+> /dev/null'); | |
open(STDOUT, "> $TRMLOG"); | |
open(STDERR, '+>& STDOUT'); | |
if('startstart' eq $operation_mode) | |
{ | |
$SIG{TERM} = \&signalhandler_GOSTOP; | |
$SIG{INT} = \&signalhandler_GOSTOP; | |
while(0 == $RUNTIME_STOP_SIGNAL) { | |
my $server_pid = undef; | |
if($server_pid = my_fork) | |
{ | |
my $kid = -1; | |
do { | |
if(0 != $RUNTIME_STOP_SIGNAL) | |
{ kill SIGTERM, $server_pid; } | |
sleep 3; | |
$kid = waitpid($server_pid, WNOHANG); | |
} while($kid < 1); | |
my $kid_status = $?; | |
print "\n-- daemon terminated. (status-code=${kid_status})\n"; | |
} | |
else | |
{ | |
print "-- Starting daemon...\n"; | |
exec @DAEMON_CMD; | |
exit 0; | |
} | |
} | |
print "-- Stopped.\n"; | |
exit 0; | |
} | |
else | |
{ | |
exec @DAEMON_CMD; | |
} | |
# vim: ts=4 sw=4 foldmethod=marker ai | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment