I wanted a template for a service script that is versatile and easily configurable.
Along with producing similar outputs to the SSH and Samba daemons, I request the code to be as clean, simple and self explanatory as possible. Hence I removed all the comments.
Sample usage:
$ service mydaemon restart
mydaemon stop/waiting
mydaemon start/running, process 30549
Sample of similar command with the SSH daemon:
$ service ssh restart
ssh stop/waiting
ssh start/running, process 30577
Here is my service.php
script:
#!/usr/bin/php
<?php
define('NAME', basename($argv[0]));
define('RUNAS', 'root');
define('DIR', __DIR__);
define('CMD', __DIR__.'/thread.php');
define('SUDO', 'sudo -u '.RUNAS.' ');
define('LOG_FILE', '/dev/null');
define('PID_FILE', '/var/run/'.NAME.'.pid');
function writeln($string)
{
echo $string.PHP_EOL;
}
class service
{
public static function unset_pid()
{
if (is_file(PID_FILE)) unlink(PID_FILE);
}
public static function get_pid()
{
if (!is_file(PID_FILE)) return null;
$pid=file_get_contents(PID_FILE);
$process_status=null;
if (!empty($pid) && ctype_digit($pid)) $process_status=shell_exec('ps '.$pid);
if (empty($process_status) || strpos($process_status, CMD, 0)===false)
{
service::unset_pid();
return null;
}
return $pid;
}
public static function is_running()
{
return (!empty(service::get_pid()));
}
public static function start()
{
if (service::is_running())
{
writeln('start: Job is already running: '.NAME);
return true;
}
$new_pid=shell_exec('cd '.DIR.';'.SUDO.CMD.' >> '.LOG_FILE.' 2>&1 & printf $!;');
file_put_contents(PID_FILE, $new_pid);
service::status();
return service::is_running();
}
public static function stop()
{
if (!service::is_running())
{
writeln('stop: Unknown instance:');
return true;
}
shell_exec('kill '.service::get_pid());
for ($seconds=0; $seconds<60; $seconds++)
{
if (!service::is_running()) break;
sleep(1);
}
if (service::is_running())
{
writeln('Not stopped; may still be shutting down or shutdown may have failed.');
return false;
}
service::status();
return !service::is_running();
}
public static function restart()
{
if (!service::stop())
{
writeln('Aborting restart.');
return false;
}
return service::start();
}
public static function status()
{
$running=service::is_running();
if ($running) writeln(NAME.' start/running, process '.service::get_pid()); else writeln(NAME.' stop/waiting');
return $running;
}
};
if (count($argv)!=2)
{
if (count($argv)>2) writeln('Too many arguments given.');
$argv=array($argv[0], '');
}
switch (strtolower($argv[1]))
{
case 'start':
service::start();
break;
case 'stop':
service::stop();
break;
case 'restart':
service::restart();
break;
case 'status':
service::status();
break;
default:
if (!empty($argv[1])) writeln('Unknown option: '.$argv[1]);
writeln('Usage: '.$argv[0].' {start|stop|restart|status}');
break;
}
?>
Any suggestions for improvements will be appreciated.