181 lines
6.1 KiB
PHP
181 lines
6.1 KiB
PHP
<?php
|
|
/** DomFramework
|
|
* @package domframework
|
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
|
* @license BSD
|
|
*/
|
|
|
|
namespace Domframework;
|
|
|
|
require_once ("domframework/fork.php");
|
|
require_once ("domframework/file.php");
|
|
|
|
/** Manage a daemon.
|
|
* Allow to start, stop, get status of a callable method
|
|
*/
|
|
class daemon
|
|
{
|
|
/** Set the directory to store the PID of the daemon
|
|
*/
|
|
private $runDir = "/var/run";
|
|
|
|
/** The constructor check if /proc is mounted
|
|
*/
|
|
public function __construct ()
|
|
{
|
|
if (! file_exists ("/proc"))
|
|
throw new \Exception ("Can't manage daemon: /proc doesn't exists", 500);
|
|
}
|
|
|
|
/** Get/set the directory to store the PID of the daemon
|
|
* @param string|null $val The directory
|
|
*/
|
|
public function runDir ($val = null)
|
|
{
|
|
if ($val === null)
|
|
return $this->runDir;
|
|
if (! is_string ($val))
|
|
throw new \Exception ("Can not set daemon runDir: not a string", 500);
|
|
$this->runDir = "$val";
|
|
}
|
|
|
|
/** Start the callable method. The terminal is closed. All the displayed
|
|
* messages from the child are silently dropped.
|
|
* If some parameters are provided, the called child method will receive them
|
|
* This function fork and return the child PID
|
|
* @param string $name The name of daemon to start.
|
|
* @param callable $callable The callback method to use in child
|
|
* @param mixed|null $params The params to provide to child method
|
|
* @return The child PID
|
|
*/
|
|
public function start ($name, $callable, $params = array ())
|
|
{
|
|
$file = new \file ();
|
|
if (! $file->is_writeable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
|
$this->runDir), 500);
|
|
if (! $file->is_readable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
|
$this->runDir), 500);
|
|
if ($file->file_exists ($this->runDir."/$name.pid"))
|
|
{
|
|
$pid = trim ($file->file_get_contents ($this->runDir."/$name.pid"));
|
|
if (file_exists ("/proc/$pid"))
|
|
throw new \Exception (sprintf (
|
|
"Can't start the daemon: already running with PID %d", $pid), 500);
|
|
}
|
|
$fork = new \fork ();
|
|
$pid = $fork->startDetachedChild ($name, $callable, $params);
|
|
file_put_contents ($this->runDir."/$name.pid", $pid);
|
|
return $pid;
|
|
}
|
|
|
|
/** Stop a $name daemon
|
|
* @param string $name The name of daemon to stop. The name must be the same
|
|
* as the name used in the start method
|
|
* @param integer $maxWaitStop The waiting maximum time after SIGTERM before
|
|
* sending SIGKILL
|
|
* @param integer $maxWaitKill The waiting maximum time after SIGKILL before
|
|
* raising an error
|
|
*/
|
|
public function stop ($name, $maxWaitStop = 3, $maxWaitKill = 3)
|
|
{
|
|
$file = new \file ();
|
|
if (! $file->is_writeable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
|
$this->runDir), 500);
|
|
if (! $file->is_readable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
|
$this->runDir), 500);
|
|
if (! $file->file_exists ($this->runDir."/$name.pid"))
|
|
throw new \Exception (sprintf (
|
|
"PID file %s not found : can't stop the daemon",
|
|
$this->runDir."/$name.pid"), 500);
|
|
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
|
if (! file_exists ("/proc/$pid"))
|
|
{
|
|
$file->unlink ($this->runDir."/$name.pid");
|
|
throw new \Exception (
|
|
"Can't stop daemon $name. There is no process with the PID $pid",
|
|
500);
|
|
}
|
|
posix_kill ($pid, SIGTERM);
|
|
usleep (10000);
|
|
$startWait = time ();
|
|
while (time () < $startWait + $maxWaitStop)
|
|
{
|
|
// If the child is zombie and is connected to me, pcntl_waitpid allow it
|
|
// to be destroyed to close correctely the parent
|
|
pcntl_waitpid ($pid, $status, WNOHANG);
|
|
if (! file_exists ("/proc/$pid"))
|
|
{
|
|
$file->unlink ($this->runDir."/$name.pid");
|
|
return true;
|
|
}
|
|
usleep (100000);
|
|
echo ".";
|
|
}
|
|
posix_kill ($pid, SIGKILL);
|
|
$startWait = time ();
|
|
while (time () < $startWait + $maxWaitKill)
|
|
{
|
|
if (! file_exists ("/proc/$pid"))
|
|
{
|
|
$file->unlink ($this->runDir."/$name.pid");
|
|
return true;
|
|
}
|
|
usleep (100000);
|
|
echo "X";
|
|
}
|
|
throw new \Exception ("Can't stop and can't kill the process $pid", 500);
|
|
}
|
|
|
|
/** Status of a daemon
|
|
* @param string $name The name of daemon to have status. The name must be
|
|
* the same as the name used in the start method
|
|
*/
|
|
public function status ($name)
|
|
{
|
|
$file = new \file ();
|
|
if (! $file->is_writeable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
|
$this->runDir), 500);
|
|
if (! $file->is_readable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
|
$this->runDir), 500);
|
|
if (! $file->file_exists ($this->runDir."/$name.pid"))
|
|
return "The daemon is be stopped";
|
|
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
|
if (! file_exists ("/proc/$pid"))
|
|
{
|
|
$file->unlink ($this->runDir."/$name.pid");
|
|
return "The daemon is stopped, but the PID file was remaining. Delete";
|
|
}
|
|
return "The daemon is running on PID $pid\n";
|
|
}
|
|
|
|
/** Send a HUP Signal to the daemon
|
|
* @param string $name The name of daemon to HUP. The name must be
|
|
* the same as the name used in the start method
|
|
*/
|
|
public function reload ($name)
|
|
{
|
|
$file = new \file ();
|
|
if (! $file->is_writeable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
|
$this->runDir), 500);
|
|
if (! $file->is_readable ($this->runDir))
|
|
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
|
$this->runDir), 500);
|
|
if (! $file->file_exists ($this->runDir."/$name.pid"))
|
|
return "The daemon is be stopped";
|
|
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
|
if (! file_exists ("/proc/$pid"))
|
|
{
|
|
$file->unlink ($this->runDir."/$name.pid");
|
|
return "The daemon is stopped, but the PID file was remaining. Delete";
|
|
}
|
|
return posix_kill ($pid, SIGHUP);
|
|
}
|
|
}
|