home *** CD-ROM | disk | FTP | other *** search
- <?php
- /* vim: set noai expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
-
- /**
- * System_Daemon turns PHP-CLI scripts into daemons.
- *
- * PHP version 5
- *
- * @category System
- * @package System_Daemon
- * @author Kevin van Zonneveld <kevin@vanzonneveld.net>
- * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD Licence
- * @version SVN: Release: $Id: Daemon.php 134 2008-05-22 15:41:53Z kevin $
- * @link http://trac.plutonia.nl/projects/system_daemon
- */
-
- // Autoloader borrowed from PHP_CodeSniffer, see function for credits
- spl_autoload_register(array("System_Daemon", "autoload"));
-
- /**
- * System_Daemon. Create daemons with practicle functions
- * like $daemon->start()
- *
- * Requires PHP build with --enable-cli --with-pcntl.
- * Only runs on *NIX systems, because Windows lacks of the pcntl ext.
- *
- * PHP version 5
- *
- * @category System
- * @package System_Daemon
- * @author Kevin van Zonneveld <kevin@vanzonneveld.net>
- * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD Licence
- * @version SVN: Release: $Id: Daemon.php 134 2008-05-22 15:41:53Z kevin $
- * @link http://trac.plutonia.nl/projects/system_daemon
- *
- */
- class System_Daemon
- {
- // Make these corresponding with PEAR
- // Ensures compatibility while maintaining independency
-
- /**
- * System is unusable
- */
- const LOG_EMERG = 0;
-
- /**
- * Immediate action required
- */
- const LOG_ALERT = 1;
-
- /**
- * Critical conditions
- */
- const LOG_CRIT = 2;
-
- /**
- * Error conditions
- */
- const LOG_ERR = 3;
-
- /**
- * Warning conditions
- */
- const LOG_WARNING = 4;
-
- /**
- * Normal but significant
- */
- const LOG_NOTICE = 5;
-
- /**
- * Informational
- */
- const LOG_INFO = 6;
-
- /**
- * Debug-level messages
- */
- const LOG_DEBUG = 7;
-
-
-
- /**
- * The current process identifier
- *
- * @var integer
- */
- static private $_processId = 0;
-
- /**
- * Wether the our daemon is being killed
- *
- * @var boolean
- */
- static private $_isDying = false;
-
- /**
- * Wether the current process is a forked child
- *
- * @var boolean
- */
- static private $_processIsChild = false;
-
- /**
- * Wether SAFE_MODE is on or off. This is important for ini_set
- * behavior
- *
- * @var boolean
- */
- static private $_safeMode = false;
-
- /**
- * Available log levels
- *
- * @var array
- */
- static private $_logLevels = array(
- self::LOG_EMERG => "emerg",
- self::LOG_ALERT => "alert",
- self::LOG_CRIT => "crit",
- self::LOG_ERR => "err",
- self::LOG_WARNING => "warning",
- self::LOG_NOTICE => "notice",
- self::LOG_INFO => "info",
- self::LOG_DEBUG => "debug"
- );
-
- /**
- * Holds Option Object
- *
- * @var mixed object or boolean
- */
- static private $_optObj = false;
-
- /**
- * Holds OS Object
- *
- * @var mixed object or boolean
- */
- static private $_osObj = false;
-
- /**
- * Definitions for all Options
- *
- * @var array
- * @see setOption()
- * @see getOption()
- */
- static private $_optionDefinitions = array(
- "usePEAR" => array(
- "type" => "boolean",
- "default" => true,
- "punch" => "Wether to run this class using PEAR",
- "detail" => "Will run standalone when false",
- "required" => true
- ),
- "usePEARLogInstance" => array(
- "type" => "boolean|object",
- "default" => false,
- "punch" => "Accepts a PEAR_Log instance to handle all logging",
- "detail" => "This will replace System_Daemon's own logging facility",
- "required" => true
- ),
-
- "authorName" => array(
- "type" => "string/0-50",
- "punch" => "Author name",
- "example" => "Kevin van zonneveld",
- "detail" => "Required for forging init.d script"
- ),
- "authorEmail" => array(
- "type" => "string/email",
- "punch" => "Author e-mail",
- "example" => "kevin@vanzonneveld.net",
- "detail" => "Required for forging init.d script"
- ),
- "appName" => array(
- "type" => "string/unix",
- "punch" => "The application name",
- "example" => "logparser",
- "detail" => "Must be UNIX-proof; Required for running daemon",
- "required" => true
- ),
- "appDescription" => array(
- "type" => "string",
- "punch" => "Daemon description",
- "example" => "Parses logfiles of vsftpd and stores them in MySQL",
- "detail" => "Required for forging init.d script"
- ),
- "appDir" => array(
- "type" => "string/existing_dirpath",
- "default" => "@dirname({SERVER.SCRIPT_NAME})",
- "punch" => "The home directory of the daemon",
- "example" => "/usr/local/logparser",
- "detail" => "Highly recommended to set this yourself",
- "required" => true
- ),
- "appExecutable" => array(
- "type" => "string/existing_filepath",
- "default" => "@basename({SERVER.SCRIPT_NAME})",
- "punch" => "The executable daemon file",
- "example" => "logparser.php",
- "detail" => "Recommended to set this yourself; Required for init.d",
- "required" => true
- ),
-
- "logVerbosity" => array(
- "type" => "number/0-7",
- "default" => self::LOG_INFO,
- "punch" => "Messages below this log level are ignored",
- "example" => "",
- "detail" => "Not written to logfile; not displayed on screen",
- "required" => true
- ),
- "logLocation" => array(
- "type" => "string/creatable_filepath",
- "default" => "/var/log/{OPTIONS.appName}.log",
- "punch" => "The log filepath",
- "example" => "/var/log/logparser_daemon.log",
- "detail" => "",
- "required" => true
- ),
-
- "appRunAsUID" => array(
- "type" => "number/0-65000",
- "default" => 0,
- "punch" => "The user id under which to run the process",
- "example" => "1000",
- "detail" => "Defaults to root which is insecure!",
- "required" => true
- ),
- "appRunAsGID" => array(
- "type" => "number/0-65000",
- "default" => 0,
- "punch" => "The group id under which to run the process",
- "example" => "1000",
- "detail" => "Defaults to root which is insecure!",
- "required" => true
- ),
- "appPidLocation" => array(
- "type" => "string/creatable_filepath",
- "default" => "/var/run/{OPTIONS.appName}.pid",
- "punch" => "The pid filepath",
- "example" => "/var/run/logparser.pid",
- "detail" => "",
- "required" => true
- ),
- "appDieOnIdentityCrisis" => array(
- "type" => "boolean",
- "default" => true,
- "punch" => "Kill daemon if it cannot assume the identity",
- "detail" => "",
- "required" => true
- ),
-
- "sysMaxExecutionTime" => array(
- "type" => "number",
- "default" => 0,
- "punch" => "Maximum execution time of each script in seconds",
- "detail" => "0 is infinite"
- ),
- "sysMaxInputTime" => array(
- "type" => "number",
- "default" => 0,
- "punch" => "Maximum time to spend parsing request data",
- "detail" => "0 is infinite"
- ),
- "sysMemoryLimit" => array(
- "type" => "string",
- "default" => "128M",
- "punch" => "Maximum amount of memory a script may consume",
- "detail" => "0 is infinite"
- ),
- );
-
- /**
- * Available signal handlers
- * setSigHandler can overwrite these values individually.
- *
- * @var array
- * @see setSigHandler()
- */
- static private $_sigHandlers = array(
- SIGCONT => array("System_Daemon", "defaultSigHandler"),
- SIGALRM => array("System_Daemon", "defaultSigHandler"),
- SIGINT => array("System_Daemon", "defaultSigHandler"),
- SIGABRT => array("System_Daemon", "defaultSigHandler"),
- SIGTERM => array("System_Daemon", "defaultSigHandler"),
- SIGHUP => array("System_Daemon", "defaultSigHandler"),
- SIGUSR1 => array("System_Daemon", "defaultSigHandler"),
- SIGCHLD => array("System_Daemon", "defaultSigHandler")
- );
-
-
-
- /**
- * Making the class non-abstract with a private constructor does a better
- * job of preventing instantiation than just marking the class as abstract.
- *
- * @see start()
- */
- private function __construct()
- {
-
- }
-
-
-
- /**
- * Autoload static method for loading classes and interfaces.
- * Code from the PHP_CodeSniffer package by Greg Sherwood and
- * Marc McIntyre
- *
- * @param string $className The name of the class or interface.
- *
- * @return void
- */
- static public function autoload($className)
- {
- $parent = 'System_';
- $parent_len = strlen($parent);
- if (substr($className, 0, $parent_len) == $parent) {
- $newClassName = substr($className, $parent_len);
- } else {
- $newClassName = $className;
- }
-
- $path = str_replace('_', '/', $newClassName).'.php';
-
- if (is_file(dirname(__FILE__).'/'.$path) === true) {
- // Check standard file locations based on class name.
- include dirname(__FILE__).'/'.$path;
- } else {
- // Everything else.
- @include $path;
- }
-
- }//end autoload()
-
-
- /**
- * Spawn daemon process.
- *
- * @return boolean
- * @see stop()
- * @see autoload()
- * @see _optionsInit()
- * @see _summon()
- */
- static public function start()
- {
-
- // Quickly initialize some defaults like usePEAR
- // by adding the $premature flag
- self::_optionsInit(true);
-
- // To run as a part of PEAR
- if (self::getOption("usePEAR")) {
- // SPL's autoload will make sure classes are automatically loaded
- if (class_exists('PEAR', true) === false) {
- $msg = "PEAR not found. Install PEAR or run with option: ".
- "usePEAR = false";
- trigger_error($msg, E_USER_ERROR);
- }
-
- if (class_exists('PEAR_Exception', true) === false) {
- $msg = "PEAR_Exception not found?!";
- trigger_error($msg, E_USER_ERROR);
- }
-
- if (class_exists('System_Daemon_Exception', true) === false) {
- // PEAR_Exception is OK. PEAR was found already.
- throw new PEAR_Exception('Class System_Daemon_Exception not found');
- }
- }
-
- // Check the PHP configuration
- if (!defined("SIGHUP")) {
- $msg = "PHP is compiled without --enable-pcntl directive";
- if (self::getOption("usePEAR")) {
- throw new System_Daemon_Exception($msg);
- } else {
- trigger_error($msg, E_USER_ERROR);
- }
- }
-
- // Check for CLI
- if ((php_sapi_name() != 'cli')) {
- $msg = "You can only create daemon from the command line";
- if (self::getOption("usePEAR")) {
- throw new System_Daemon_Exception($msg);
- } else {
- trigger_error($msg, E_USER_ERROR);
- }
- }
-
- // Initialize & check variables
- if (self::_optionsInit(false) === false) {
- if (is_object(self::$_optObj) && is_array(self::$_optObj->errors)) {
- foreach (self::$_optObj->errors as $error) {
- self::log(self::LOG_NOTICE, $error);
- }
- }
-
- $msg = "Crucial options are not set. Review log:";
- if (self::getOption("usePEAR")) {
- throw new System_Daemon_Exception($msg);
- } else {
- trigger_error($msg, E_USER_ERROR);
- }
- }
-
- // Become daemon
- self::_summon();
-
- return true;
-
- }//end start()
-
- /**
- * Stop daemon process.
- *
- * @return void
- * @see start()
- */
- static public function stop()
- {
- self::log(self::LOG_INFO, "stopping ".
- self::getOption("appName")." daemon",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- self::_die();
- }//end stop()
-
-
- /**
- * Overrule or add signal handlers.
- *
- * @param string $signal Signal constant (e.g. SIGHUP)
- * @param mixed $handler Which handler to call on signal
- *
- * @return boolean
- * @see $_sigHandlers
- */
- static public function setSigHandler($signal, $handler)
- {
- if (!isset(self::$_sigHandlers[$signal])) {
- // The signal should be defined already
- self::log(self::LOG_NOTICE, "You can only overrule a ".
- "handler that has been defined already.",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- return false;
- }
-
- // Overwrite on existance
- self::$_sigHandlers[$signal] = $handler;
- return true;
- }//end setSigHandler()
-
- /**
- * Sets any option found in $_optionDefinitions
- * Public interface to talk with with private option methods
- *
- * @param string $name Name of the Option
- * @param mixed $value Value of the Option
- *
- * @return boolean
- */
- static public function setOption($name, $value)
- {
- if (!self::_optionObjSetup()) {
- return false;
- }
-
- return self::$_optObj->setOption($name, $value);
- }//end setOption()
-
- /**
- * Sets an array of options found in $_optionDefinitions
- * Public interface to talk with with private option methods
- *
- * @param array $use_options Array with Options
- *
- * @return boolean
- */
- static public function setOptions($use_options)
- {
- if (!self::_optionObjSetup()) {
- return false;
- }
-
- return self::$_optObj->setOptions($use_options);
- }//end setOptions()
-
- /**
- * Gets any option found in $_optionDefinitions
- * Public interface to talk with with private option methods
- *
- * @param string $name Name of the Option
- *
- * @return mixed
- */
- static public function getOption($name)
- {
- if (!self::_optionObjSetup()) {
- return false;
- }
-
- return self::$_optObj->getOption($name);
- }//end getOption()
-
- /**
- * Gets an array of options found
- *
- * @return array
- */
- static public function getOptions()
- {
- if (!self::_optionObjSetup()) {
- return false;
- }
-
- return self::$_optObj->getOptions();
- }//end setOptions()
-
-
- /**
- * Almost every deamon requires a log file, this function can
- * facilitate that. Also handles class-generated errors, chooses
- * either PEAR handling or PEAR-independant handling, depending on:
- * self::getOption("usePEAR").
- * Also supports PEAR_Log if you referenc to a valid instance of it
- * in self::getOption("usePEARLogInstance").
- *
- * It logs a string according to error levels specified in array:
- * self::$_logLevels (0 is fatal and handles daemon's death)
- *
- * @param integer $level What function the log record is from
- * @param string $str The log record
- * @param string $file What code file the log record is from
- * @param string $class What class the log record is from
- * @param string $function What function the log record is from
- * @param integer $line What code line the log record is from
- *
- * @throws System_Daemon_Exception
- * @return boolean
- * @see _logLevels
- * @see logLocation
- */
- static public function log($level, $str, $file = false, $class = false,
- $function = false, $line = false)
- {
- // If verbosity level is not matched, don't do anything
- if (self::getOption("logVerbosity") === null
- || self::getOption("logVerbosity") === false) {
- // Somebody is calling log before launching daemon..
- // fair enough, but we have to init some log options
- self::_optionsInit(true);
- }
-
- if (!self::getOption("appName")) {
- // Not logging for anything without a name
- return false;
- }
-
- if ($level > self::getOption("logVerbosity")) {
- return true;
- }
-
- // Make use of a PEAR_Log() instance
- if (self::getOption("usePEARLogInstance") !== false) {
- self::getOption("usePEARLogInstance")->log($str, $level);
- return true;
- }
-
- // Save resources if arguments are passed.
- // But by falling back to debug_backtrace() it still works
- // if someone forgets to pass them.
- if (function_exists("debug_backtrace") && ($file == false
- || $class == false || $function == false || $line == false)) {
- $dbg_bt = @debug_backtrace();
- $class = (isset($dbg_bt[1]["class"])?$dbg_bt[1]["class"]:"");
- $function = (isset($dbg_bt[1]["function"])?$dbg_bt[1]["function"]:"");
- $file = $dbg_bt[0]["file"];
- $line = $dbg_bt[0]["line"];
- }
-
- // Determine what process the log is originating from and forge a logline
- //$str_ident = "@".substr(self::_whatIAm(), 0, 1)."-".posix_getpid();
- $str_date = "[".date("M d H:i:s")."]";
- $str_level = str_pad(self::$_logLevels[$level]."", 8, " ", STR_PAD_LEFT);
- $log_line = $str_date." ".$str_level.": ".$str; // $str_ident
- if ($level < self::LOG_NOTICE) {
- $log_line .= " [l:".$line."]";
- }
-
- $non_debug = ($level < self::LOG_DEBUG);
- $log_succeeded = true;
- $log_echoed = false;
-
- if (!self::isInBackground() && $non_debug && !$log_echoed) {
- // It's okay to echo if you're running as a foreground process.
- // Maybe the command to write an init.d file was issued.
- // In such a case it's important to echo failures to the
- // STDOUT
- echo $log_line."\n";
- $log_echoed = true;
- // but still try to also log to file for future reference
- }
-
- // 'Touch' logfile
- if (!file_exists(self::getOption("logLocation"))) {
- file_put_contents(self::getOption("logLocation"), "");
- }
-
- // Not writable even after touch? Allowed to echo again!!
- if (!is_writable(self::getOption("logLocation"))
- && $non_debug && !$log_echoed) {
- echo $log_line."\n";
- $log_echoed = true;
- $log_succeeded = false;
- }
-
- // Append to logfile
- if (!file_put_contents(self::getOption("logLocation"),
- $log_line."\n", FILE_APPEND)) {
- $log_succeeded = false;
- }
-
- // These are pretty serious errors
- if ($level < self::LOG_WARNING) {
- // So Throw an exception
- if (self::getOption("usePEAR")) {
- throw new System_Daemon_Exception($log_line);
- }
- // An emergency logentry is reason for the deamon to
- // die immediately
- if ($level == self::LOG_EMERG) {
- self::_die();
- }
- }
-
- return $log_succeeded;
-
- }//end log()
-
- /**
- * Uses OS class to write an: 'init.d' script on the filesystem
- *
- * @param boolean $overwrite May the existing init.d file be overwritten?
- *
- * @return boolean
- */
- static public function writeAutoRun($overwrite=false)
- {
- // Init Options (needed for properties of init.d script)
- if (self::_optionsInit(false) === false) {
- return false;
- }
-
- // Init OS Object
- if (!self::_osObjSetup()) {
- return false;
- }
-
- // Get daemon properties
- $options = self::getOptions();
-
- // Try to write init.d
- if (($res = self::$_osObj->writeAutoRun($options, $overwrite)) === false) {
- if (is_array(self::$_osObj->errors)) {
- foreach (self::$_osObj->errors as $error) {
- self::log(self::LOG_NOTICE, $error);
- }
- }
- self::log(self::LOG_WARNING, "Unable to create startup file.");
- return false;
- }
-
- if ($res === true) {
- self::log(self::LOG_NOTICE, "Startup was already written");
- } else {
- self::log(self::LOG_NOTICE, "Startup written to ".$res."");
- }
-
- return true;
- }//end writeAutoRun()
-
- /**
- * Default signal handler.
- * You can overrule various signals with the
- * setSigHandler() method
- *
- * @param integer $signo The posix signal received.
- *
- * @return void
- * @see setSigHandler()
- * @see $_sigHandlers
- */
- static public function defaultSigHandler( $signo )
- {
- // Must be public or else will throw a
- // fatal error: Call to private method
-
- self::log(self::LOG_DEBUG, self::getOption("appName").
- " daemon received signal: ".$signo,
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
-
- switch ($signo) {
- case SIGTERM:
- // Handle shutdown tasks
- if (self::isInBackground()) {
- self::_die();
- } else {
- exit;
- }
- break;
- case SIGHUP:
- // Handle restart tasks
- self::log(self::LOG_INFO, self::getOption("appName").
- " daemon received signal: restart",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- break;
- case SIGCHLD:
- self::log(self::LOG_INFO, self::getOption("appName").
- " daemon received signal: hold",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- while (pcntl_wait($status, WNOHANG OR WUNTRACED) > 0) {
- usleep(1000);
- }
- break;
- default:
- // Handle all other signals
- break;
- }
- }//end defaultSigHandler()
-
- /**
- * Wether the class is already running in the background
- *
- * @return boolean
- */
- static public function isInBackground()
- {
- return self::$_processIsChild;
- }//end isInBackground()
-
- /**
- * Wether the our daemon is being killed, you might
- * want to include this in your loop
- *
- * @return boolean
- */
- static public function isDying()
- {
- return self::$_isDying;
- }//end isDying()
-
- /**
- * Check if a previous process with same pidfile was already running
- *
- * @return boolean
- */
- static public function isRunning()
- {
- if(!file_exists(self::getOption("appPidLocation"))) return false;
- $pid = @file_get_contents(self::getOption("appPidLocation"));
-
- if ($pid !== false) {
- // Ping app
- if (!posix_kill(intval($pid), 0)) {
- // Not responding so unlink pidfile
- @unlink(self::getOption("appPidLocation"));
- self::log(self::LOG_WARNING, "".self::getOption("appName").
- " daemon orphaned pidfile ".
- "found and removed: ".self::getOption("appPidLocation"),
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- return false;
- } else {
- return true;
- }
- } else {
- return false;
- }
- }//end isRunning()
-
-
-
- /**
- * Put the running script in background
- *
- * @return void
- */
- static private function _summon()
- {
-
- self::log(self::LOG_INFO, "starting ".self::getOption("appName").
- " daemon, output in: ".
- self::getOption("logLocation"),
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
-
- // Important for daemons
- // See http://nl2.php.net/manual/en/function.pcntl-signal.php
- declare(ticks = 1);
-
- // Setup signal handlers
- // Handlers for individual signals can be overrulled with
- // setSigHandler()
- foreach (self::$_sigHandlers as $signal=>$handler) {
- pcntl_signal($signal, $handler);
- }
-
- // Allowed?
- if (self::isRunning()) {
- self::log(self::LOG_EMERG, "".self::getOption("appName").
- " daemon is still running. ".
- "exiting",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- }
-
- // Reset Process Information
- self::$_safeMode = ((boolean)@ini_get("safe_mode") === false) ?
- false : true;
- self::$_processId = 0;
- self::$_processIsChild = false;
-
- // Fork process!
- if (!self::_fork()) {
- self::log(self::LOG_EMERG, "".self::getOption("appName").
- " daemon was unable to fork",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- }
-
- // Assume specified identity (uid & gid)
- if (!posix_setuid(self::getOption("appRunAsUID")) ||
- !posix_setgid(self::getOption("appRunAsGID"))) {
- $lvl = self::LOG_CRIT;
- $swt = "off";
- if (self::getOption("appDieOnIdentityCrisis")) {
- $lvl = self::LOG_EMERG;
- $swt = "on";
- }
-
- self::log($lvl, "".self::getOption("appName").
- " daemon was unable assume ".
- "identity (uid=".self::getOption("appRunAsUID").", gid=".
- self::getOption("appRunAsGID").") ".
- "and appDieOnIdentityCrisis was ". $swt,
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- }
-
- // Additional PID succeeded check
- if (!is_numeric(self::$_processId) || self::$_processId < 1) {
- self::log(self::LOG_EMERG, "".self::getOption("appName").
- " daemon didn't have a valid ".
- "pid: '".self::$_processId."'",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- }
-
- if (!file_put_contents(self::getOption("appPidLocation"),
- self::$_processId)) {
- self::log(self::LOG_EMERG, "".self::getOption("appName").
- " daemon was unable ".
- "to write to pidfile: ".self::getOption("appPidLocation")."",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- }
-
- // System settings
- if (!self::$_safeMode) {
- $options = self::getOptions();
- if (is_array($options)) {
- foreach ($options as $name=>$value) {
- if (substr($name, 0, 3) == "sys" ) {
- ini_set($name, $value);
- }
- }
- }
- }
- set_time_limit(0);
- ob_implicit_flush();
-
-
- // Change dir & umask
- @chdir(self::getOption("appDir"));
- @umask(0);
- }//end _summon()
-
- /**
- * Fork process and kill parent process, the heart of the 'daemonization'
- *
- * @return boolean
- */
- static private function _fork()
- {
- self::log(self::LOG_DEBUG, "forking ".self::getOption("appName").
- " daemon",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- $pid = pcntl_fork();
- if ( $pid == -1 ) {
- // Error
- self::log(self::LOG_WARNING, "".self::getOption("appName").
- " daemon could not be forked",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- return false;
- } else if ($pid) {
- // Parent
- self::log(self::LOG_DEBUG, "ending ".self::getOption("appName").
- " parent process",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- // Die without attracting attention
- exit();
- } else {
- // Child
- self::$_processIsChild = true;
- self::$_isDying = false;
- self::$_processId = posix_getpid();
- return true;
- }
- }//end _fork()
-
- /**
- * Return what the current process is: child or parent
- *
- * @return string
- */
- static private function _whatIAm()
- {
- return (self::isInBackground()?"child":"parent");
- }//end _whatIAm()
-
- /**
- * Sytem_Daemon::_die()
- * Kill the daemon
- *
- * @return void
- */
- static private function _die()
- {
- if (!self::isDying()) {
- self::$_isDying = true;
- if (!self::isInBackground() ||
- !file_exists(self::getOption("appPidLocation"))) {
- self::log(self::LOG_INFO, "Not stopping ".
- self::getOption("appName").
- ", daemon was not running",
- __FILE__, __CLASS__, __FUNCTION__, __LINE__);
- return false;
- }
-
- @unlink(self::getOption("appPidLocation"));
- exit();
- }
- }//end _die()
-
-
- /**
- * Sets up Option Object instance
- *
- * @return boolean
- */
- static private function _osObjSetup()
- {
- // Create Option Object if nescessary
- if (self::$_osObj === false) {
- self::$_osObj = new System_Daemon_OS();
- }
-
- // Still false? This was an error!
- if (self::$_osObj === false) {
- self::log(self::LOG_EMERG, "Unable to setup OS object. ");
- return false;
- }
-
- return true;
- }
-
- /**
- * Sets up Option Object instance
- *
- * @return boolean
- */
- static private function _optionObjSetup()
- {
- // Create Option Object if nescessary
- if (self::$_optObj === false) {
- self::$_optObj = new System_Daemon_Options(self::$_optionDefinitions);
- }
-
- // Still false? This was an error!
- if (self::$_optObj === false) {
- self::log(self::LOG_EMERG, "Unable to setup Options object. ".
- "You must provide valid option definitions");
- return false;
- }
-
- return true;
- }
-
- /**
- * Checks if all the required options are set.
- * Initializes, sanitizes & defaults unset variables
- *
- * @param boolean $premature Whether to do a premature option init
- *
- * @return mixed integer or boolean
- */
- static private function _optionsInit($premature=false)
- {
- if (!self::_optionObjSetup()) {
- return false;
- }
-
- return self::$_optObj->init($premature);
- }//end _optionsInit()
-
- }//end class
- ?>