/overwatchd/lib/classes/daemon.php
PHP | 130 lines | 124 code | 0 blank | 6 comment | 32 complexity | 82fb49a2c6974d3280dc9d082916b71b MD5 | raw file
- <?php abstract class Daemon implements iExtensionsRequired, iReconfigurable, iSignalHandler {
- protected static $Detached = FALSE;
- protected static $Sleep = 30;
- protected static $Queue = array ();
- protected static $Cyclers = array ();
- protected static $SigMap = array ();
- public static function __GetRequiredExtensions () {return (array ('pcntl', 'posix'));}
- public static function __Signals ($Sig = NULL) {
- if (NULL === $Sig) return (array (SIGHUP, SIGINT, SIGQUIT, SIGTERM));
- switch ($Sig) {
- case SIGINT: case SIGQUIT: case SIGTERM:
- Out::I (Msg::SigHandled, $Sig);
- self::Down ();
- break;
- case SIGHUP:
- Out::I (Msg::SigHandled, $Sig);
- self::Push2Q (array (__CLASS__, 'ParseConfig'));
- break;
- }
- }
- public static function Detach () {
- if (Options::NoFork ()) {
- Out::I (Msg::NotForkingOut);
- return (NULL);
- }
- Out::I (Msg::ForkingOut);
- switch (pcntl_fork ()) {
- default: exit (0);
- case -1: Out::W (Msg::ForkFailed); return (NULL);
- case 0:
- file_put_contents ($PidFile = Options::PidFile (), ($Pid = getmypid ())."\n") or Out::W (Msg::PidSaveError, $Pid, $PidFile);
- ini_set ('display_errors', 0);
- ini_set ('log_errors', 1);
- ini_set ('error_log', 'syslog');
- posix_setsid ();
- self::$Detached = TRUE;
- fclose (STDIN);
- fclose (STDOUT);
- fclose (STDERR);
- }
- }
- public static function ParseConfig () {
- if (is_readable ($Filename = Options::Config ())) {
- $Config = parse_ini_file ($Filename, TRUE);
- Out::D (Msg::ConfigDump, $Filename, print_r ($Config, TRUE));
- foreach ($Config as $Class => $ClassConfig) if (class_exists ($Class) and HasInterface ($Class, 'iReconfigurable')) {
- Out::I (Msg::Reconfigure, $Class);
- call_user_func (array ($Class, 'Reconfigure'), $ClassConfig);
- }
- } else Out::W (Msg::ReadFileFail, $Filename);
- }
- public static function Reconfigure (array $Config) {
- if (array_key_exists ('sleep', $Config)) {
- Out::I (Msg::ConfigGot, 'sleep', $Sleep = $Config ['sleep']);
- if ($Sleep >= 1) {
- Out::I (Msg::ConfigApplied, 'sleep', self::$Sleep = $Sleep);
- } else Out::W (Msg::BadSleep, $Sleep, self::$Sleep);
- }
- // try to change user and group
- if (array_key_exists ('user', $Config) and strlen ($UID = $Config ['user'])) {
- Out::I (Msg::ConfigGot, 'user', $UID);
- // determine numbers
- $UID = ($UID !== (string) (int) $UID) ? posix_getpwnam ($UID) : posix_getpwuid ((int) $UID);
- if (array_key_exists ('group', $Config) and strlen ($GID = $Config ['group'])) {
- Out::I (Msg::ConfigGot, 'group', $GID);
- $GID = ($GID !== (string) (int) $GID) ? posix_getgrnam ($GID) : posix_getgrgid ((int) $GID);
- $GID = $GID ['gid'];
- } else $GID = $UID ['gid'];
- $UID = $UID ['uid'];
- // changing if nessesary
- if ($GID !== ($CurGID = posix_getgid ())) {
- if (posix_setgid ($GID)) {
- Out::I (Msg::ChangedID, 'GID', $GID);
- } else Out::W (Msg::ChangeIDFailed, 'GID', $GID, $CurGID);
- } else Out::I (Msg::NotChangingID, 'GID', $GID);
- if ($UID !== ($CurUID = posix_getuid ())) {
- if (posix_setuid ($UID)) {
- Out::I (Msg::ChangedID, 'UID', $UID);
- } else Out::W (Msg::ChangeIDFailed, 'UID', $UID, $CurUID);
- } else Out::I (Msg::NotChangingID, 'UID', $UID);
- }
- }
- public static function Detached () {return (self::$Detached);}
- public static function Push2Q ($Callback, $Args = NULL) {
- if (! is_callable ($Callback)) return (FALSE);
- $Callback = array ('cb' => $Callback);
- $Callback ['args'] = (NULL === $Args) ? array () : $Args;
- is_array ($Callback ['args']) or $Callback ['args'] = array ($Callback ['args']);
- array_push (self::$Queue, $Callback);
- }
- public static function SigHandler ($Sig = NULL) {
- if (NULL === $Sig) {
- foreach (get_declared_classes () as $Class) if (HasInterface ($Class, 'iSignalHandler')) {
- foreach (call_user_func (array ($Class, '__Signals')) as $Sig) self::$SigMap [$Sig][] = $Class;
- }
- Out::I (Msg::SigInstall);
- foreach (array_keys (self::$SigMap) as $Sig) pcntl_signal ($Sig, array (__CLASS__, __FUNCTION__));
- return (TRUE);
- }
- Out::I (Msg::SigCaught, $Sig);
- if (array_key_exists ($Sig, self::$SigMap)) {
- foreach (self::$SigMap [$Sig] as $Class) {
- if (is_callable ($Callback = array ($Class, '__Signals'))) {
- Out::I (Msg::Callback, implode ('::', $Callback));
- call_user_func ($Callback, $Sig);
- } else Out::W (Msg::Uncallable, implode ('::', $Callback));
- }
- } else Out::W (Msg::SigUnknown, $Sig);
- }
- public static function Main () {
- Out::I (Msg::MainLoop);
- foreach (get_declared_classes () as $Class) if (HasInterface ($Class, 'iCycler')) array_push (self::$Cyclers, $Class);
- while (TRUE) {
- for ($i = 1; $i < self::$Sleep; $i += 1) sleep (1); // this quantisation is needed so that any signal handled will not break the whole sleep
- // run filters
- if (is_array ($Lines = DB::Fetch ())) foreach ($Lines as $Line) Filter::Examine ($Line);
- Filter::Commit ();
- // process queue
- foreach (self::$Queue as $Callback) call_user_func_array ($Callback ['cb'], $Callback ['args']);
- self::$Queue = array ();
- // process cyclers
- foreach (self::$Cyclers as $Cycler) call_user_func (array ($Cycler, 'Cycle'));
- }
- }
- public static function Down () {
- Out::I (Msg::ExitingClean);
- self::$Detached and @unlink (Options::PidFile ());
- exit (0);
- }
- } ?>