📄 gnugk_wrapper.pl
字号:
# output: nonesub killGnugk{ my $pid = shift; return if ($pid <= 0); print " Killing gnugk... " if ($debug); my $nKilledProc = kill ('KILL', $pid); print " killed $nKilledProc process(es)\n" if ($debug);};# adds leading zeros# input: (int) number, (int) necessary length# output: (string) number with leading zerossub addLeadingZeros{ my ($number, $length) = @_; my $ret; return $number if (length($number) >= $length); my $zeros = "0" x $length; return substr($zeros.$number, -$length);};# check directory if it exists, is a directory and is writeable# create new directory if neccessary or die# die if file exists and is not a directory or writeable# input: (string) directory path# output: (int) 1 - is ok; 0 - failuresub checkDir{ my $dirName = shift; return 0 if ($dirName eq ''); # check if exists, create if not exist if (!(-e $dirName)) { print "$dirName direcotory doesn't exist. Creating...\n"; if (system ("mkdir -p '$dirName'") != 0) { print "Can not make directory $dirName\n $!"; return 0; }; }; # check if it is directory, writeable and executeable if (!(-w $dirName) || !(-d $dirName) || !(-x $dirName)) { print "$dirName not writeable, executeable or is not directory at all"; return 0; }; return 1;};### main #### check global variablesif ($gnugk eq ''){ die "No path to gnugk executeable set. Exiting...";};if (!(-x $gnugk)){ die "Gnugk executeable $gnugk not found or not executeable. Exiting";};if ($statusPortCheckInterval <= 0){ print "Status port check interval ivalid: $statusPortCheckInterval\n"; print " Setting to default: 60 sec.\n"; $statusPortCheckInterval = 60;};if ($socketTimeout <= 0){ print "Socket timeout value invalid: $socketTimeout\n"; print " Setting to default: 10 sec.\n"; $socketTimeout = 10;};# check directoriesdie "Directory $pidFileDir check unsuccessful" unless checkDir($pidFileDir);die "Directory $gnugkPidFileDir check unsuccessful" unless checkDir($gnugkPidFileDir);if ($copyCore){ die "Directory $coreFileDirectory check unsuccessful" unless checkDir($coreFileDirectory);};if ($logGnugkRestarts){ die "Directory $logFileDir check unsuccessful" unless checkDir($logFileDir); if (-e $logFile && !(-w $logFile)) { die "Log file $logFile not writeable"; };};# get config values from cmd linemy %conf = getConfStdin(\@ARGV); #get configuration from STDIN# get home IP address and port (needed for checking if gnugk is frozen)my ($homeIpAddress, $statusPort) = getConfFromFile( $conf{'path_to_gnugk_conf_file'}, $conf{'home_ip_address'}, $conf{'main_section_name'} );# check gnugk home IP address and portif ((!$homeIpAddress || !$statusPort) && $checkStatusPort){ die "Can not detect gnugk home IP address and port\n";};### FORK #### create child process and exit from parent process# run in background as a daemonmy $mainProcId = 0;if ($runInBackground){ print "Daemonizing...\n"; exit if ($mainProcId = fork());}else{ $mainProcId = $$;};#print "Main process pid after forking: $mainProcId\n";# create pid file, clear old one if existsmy $pidFile = "$pidFileDir/gnugk_wrapper_$homeIpAddress.pid";if (!writePidFile($pidFile, "")){ # set $pidFile to empty string to avoid trying to write to the file if # this attempt failed $pidFile = "";};# set path to gnugk pid filemy $gnugkPidFile = "$gnugkPidFileDir/gnugk_$homeIpAddress.pid";# get gnugk execution string (command that executes gnugk)# concatenate all script arguments into one stringmy $argvStr = "";foreach (@ARGV){ $argvStr .= "$_ ";};# cut trailing space$argvStr =~ s/ $//;my $gnugkExecStr = "$gnugk $argvStr --pid $gnugkPidFile > /dev/null 2>&1";### FORK #### create child process which will have to run gnugk# the other one will check if gnugk is okmy $secondaryProcId = 0;$secondaryProcId = fork();# secondary proccess # run gnugk in child processif ($secondaryProcId == 0){ # write current process pid to pid file writePidFile($pidFile, $$); # neverending loop for executing gnugk my $i = 0; my $gnugkExitCode = 0; while(1) { $i++; print "---\n\n" if ($debug); print "Executing gnugk (attempt: $i):\n" if ($debug); print " $gnugkExecStr\n" if ($debug); $gnugkExitCode = system("$gnugkExecStr"); print " gnugk exited with code $gnugkExitCode\n. Restarting gnugk process\n" if($debug); # prepare current time my $timeNow = localtime->year+1900; $timeNow .= addLeadingZeros(localtime->mon, 2); $timeNow .= addLeadingZeros(localtime->mday, 2); $timeNow .= "_"; $timeNow .= addLeadingZeros(localtime->hour, 2); $timeNow .= addLeadingZeros(localtime->min, 2); $timeNow .= addLeadingZeros(localtime->sec, 2); # copy gnugk core to core file directory if ($copyCore && -e './gnugk.core') { my $coreName = "gnugk_$timeNow.core"; print " Copying ./gnugk.core to $coreFileDirectory/$coreName\n"; system ("cp ./gnugk.core $coreFileDirectory/$coreName"); }; # log restarting event to log file if ($logGnugkRestarts) { # open file eval { open (LOGFILE, ">>$logFile") or die "Error: can not open log file $logFile\n $!"; }; # print error if ($@) { print $@ if ($debug); } # print message to log file else { print LOGFILE "[$timeNow] $homeIpAddress gnugk exited with code $gnugkExitCode\n"; close (LOGFILE); }; }; }; }# primary process# check gnugk if it is ok# kill gnugk proccess if neededelse{ # write current process pid to pid file writePidFile($pidFile, $$); # Exit if status port checking disabled if (!$checkStatusPort) { print "Status port checking disabled\n" if ($debug); exit(0); }; # neverending loop for checking status port my $sockMsg = ""; # output from socket my $sock = undef; # socket my $goodChars = 'A-Za-z0-9_;'; # character that are allowed to appear as normal status port output while (1) { # set variables to defaults $sock = undef; $sockMsg = ""; sleep ($statusPortCheckInterval); print "---\n\n" if ($debug); print "Checking gnugk status port\n" if($debug); # open socket $sock = new Net::Telnet ( Timeout => $socketTimeout, Host => $homeIpAddress, Port => $statusPort,# Prompt => '', Errmode => 'return', Telnetmode => 0, ); $sock->open(); # check socket if ($sock && !$sock->errmsg()) { print " Socket opened successfully...\n" if ($debug); #read data from sock $sockMsg = ""; my $blankLines = 0; # read from socket until buffer is empty, timeout occured or there is semicolon only in the line while (!$sock->eof() && !$sock->timed_out) { my $msg = $sock->getline(); # get one line $msg =~ s/^[^$goodChars]+|[^$goodChars]+$//; # cut out all non-good characters $sockMsg .= $msg; $blankLines++ if ($msg eq '' && $sockCheckMaxBlankLines); # increase number of blank lines if line from status port is blank last if ($blankLines >= $sockMaxBlankLines && $sockCheckMaxBlankLines); # break loop if max number of blank lines received last if ($msg eq ';'); # consider that message is received if there is semicolon only in current line }; print " Got from socket:\n" if ($debug); print " $sockMsg\n" if ($debug); # If socked timed out kill gnugk and skip all other checks if ($sock->timed_out) { print " Socket timed out\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # If access forbidden kill gnugk and skip all other checks if ($sockMsg =~ m/Access forbidden/i) { print " Access forbidden to gnugk status port\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # If no data received from gnugk kill gnugk and skip all other checks if ($sockMsg eq '') { print " No message received from gnugk status port\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # If max numbewr of blank lines received kill gnugk and skip all other checks if ($blankLines >= $sockMaxBlankLines && $sockCheckMaxBlankLines) { print " Maximum number of blank lines from status port received\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # set gnugk status port trace level to 0 to enable only direct responses to commands print " Setting status port trace level to 0...\n" if ($debug); if(!$sock->put("trace 0\r\n")) { print " Trace level adjusting unsuccessful\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; print " Trace level set: ".$sock->getline() if ($debug); # clear sockets input buffer to be sure that no unwanted input is stored in it $sock->buffer_empty; # try to get version string from gnugk # kill gnugk if unsuccessful print " Trying to get gnugk version from status port...\n" if($debug); if (!$sock->put("Version\r\n")) { print " Sending \"Version\" request unsuccessful\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; #read data from sock $sockMsg = ""; $blankLines = 0; # read from socket until buffer is empty, timeout occured or there is semicolon only in the line while (!$sock->eof() && !$sock->timed_out) { my $msg = $sock->getline(); # get one line $msg =~ s/^[^$goodChars]+|[^$goodChars]+$//; # cut out all non-good characters $sockMsg .= $msg; $blankLines++ if ($msg eq '' && $sockCheckMaxBlankLines); # increase number of blank lines if line from status port is blank last if ($blankLines >= $sockMaxBlankLines && $sockCheckMaxBlankLines); # break loop if max number of blank lines received last if ($msg eq ';'); # consider that message is received if there is semicolon only in current line }; print " Got from socket:\n" if ($debug); print " $sockMsg\n" if ($debug); # If socked timed out kill gnugk and skip all other checks if ($sock->timed_out) { print " Socket timed out\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # If no data received from gnugk kill gnugk and skip all other checks if ($sockMsg eq '') { print " No message received from gnugk status port\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; # If max numbewr of blank lines received kill gnugk and skip all other checks if ($blankLines >= $sockMaxBlankLines && $sockCheckMaxBlankLines) { print " Maximum number of blank lines from status port received\n" if ($debug); $sock->close(); killGnugk(getGnugkPid($gnugkPidFile)); next; }; $sock->close(); } # report error and killgnugk else { print " Could not create socket\n $!\n" if ($debug); killGnugk(getGnugkPid($gnugkPidFile)); }; };};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -