== Beispiel ==
Unser Daemon hört im Beispiel auf den Namen "veryimportant", was übersetzt aus dem Englischen für "sehr wichtig" steht.
Nach gültigen Konventionen wird der Daemon gestartet über ein Init Script.
== Linux Standard Base (LSB) ==
Die Linux Standard Base definiert eine Binärschnittstelle mit dem Ziel, die Kompatibilität zwischen den verschiedenen Linux-Distributionen zu verbessern.
Das Script unter /etc/init.d/veryimportant sieht wie folgt aus:
Alles anzeigen
Wir machen das Script nur für root ausführbar, aber für alle lesbar.
== Das PHP Script ==
Das Script des Hauptprogramms legen wir unter /home/veryimportant/daemon.php ab.
Die Kommandozeilenparameter "d" und "u" sind aktiviert. Mit "d" schalten wir in den Debug Modus und mit "u" nehmen wir unterschiedliche Benutzer an. Das Script soll nicht unter root, sondern einem anderen Benutzer laufen.
Bei uns "veryimportant".
Wir legen den Benutzer an mit
Das Script enthält einen Logger, der entsprechende Ausgaben an einen Output Stream leitet. Das kann einer Logdatei oder der Standard-Output sein.
Die Log Datei befindet sich unter /var/log/veryimportant.log.
Damit der Daemon nicht mehrfach gestartet werden kann verwenden wir eine PID Datei unter /var/run/veryimportant.pid.
Nun zum Quellcode:
Alles anzeigen
Unser Daemon hört im Beispiel auf den Namen "veryimportant", was übersetzt aus dem Englischen für "sehr wichtig" steht.
Nach gültigen Konventionen wird der Daemon gestartet über ein Init Script.
== Linux Standard Base (LSB) ==
Die Linux Standard Base definiert eine Binärschnittstelle mit dem Ziel, die Kompatibilität zwischen den verschiedenen Linux-Distributionen zu verbessern.
Das Script unter /etc/init.d/veryimportant sieht wie folgt aus:
Quellcode
- #!/bin/sh
- ### BEGIN INIT INFO
- # Provides: php-queue
- # Required-Start: $remote_fs mysql
- # Required-Stop: $remote_fs mysql
- # Should-Start: $network $named $time
- # Should-Stop: $network $named $time
- # Default-Start: 2 3 4 5
- # Default-Stop: 0 1 6
- # Short-Description: Starts and stops the veryimportant php daemon.
- # Description: Controls the veryimportant PHP script for me, so that
- # processing is active in all run-levels in which network
- # services are active
- ### END INIT INFO
- #
- # Author: Max Mustermann <max@mustermann.de>
- #
- # This init script conforms to LSB 3.2.0.
- #
- PATH=/bin:/usr/bin:/sbin:/usr/sbin
- DAEMON=/home/veryimportant/daemon.php
- PIDFILE=/var/run/veryimportant.pid
- test -x $DAEMON || exit 0
- . /lib/lsb/init-functions
- case "$1" in
- start)
- log_daemon_msg "Starting veryimportant processing" "veryimportant.php"
- start_daemon -p $PIDFILE $DAEMON
- log_end_msg $?
- ;;
- stop)
- log_daemon_msg "Stopping veryimportant processing" "veryimportant.php"
- killproc -p $PIDFILE $DAEMON
- log_end_msg $?
- ;;
- force-reload|restart)
- $0 stop
- $0 start
- ;;
- *)
- echo "Usage: $0 {start|stop|restart|force-reload}" >&2
- exit 2
- ;;
- esac
Wir machen das Script nur für root ausführbar, aber für alle lesbar.
== Das PHP Script ==
Das Script des Hauptprogramms legen wir unter /home/veryimportant/daemon.php ab.
Die Kommandozeilenparameter "d" und "u" sind aktiviert. Mit "d" schalten wir in den Debug Modus und mit "u" nehmen wir unterschiedliche Benutzer an. Das Script soll nicht unter root, sondern einem anderen Benutzer laufen.
Bei uns "veryimportant".
Wir legen den Benutzer an mit
Das Script enthält einen Logger, der entsprechende Ausgaben an einen Output Stream leitet. Das kann einer Logdatei oder der Standard-Output sein.
Die Log Datei befindet sich unter /var/log/veryimportant.log.
Damit der Daemon nicht mehrfach gestartet werden kann verwenden wir eine PID Datei unter /var/run/veryimportant.pid.
Nun zum Quellcode:
Quellcode
- #!/usr/bin/php
- <?php
- $options = getopt('du:');
- if ($options === FALSE) {
- die("Failed to parse command line options\n");
- }
- $debug = isset($options['d']);
- $user = isset($options['u']) ? $options['u'] : "veryimportantdaemon";
- $pidfile = "/var/run/veryimportant.pid";
- if (getmyuid() != 0) {
- die("This script must be started as root (it will revoke its privileges)\n");
- }
- if (!($passwd = posix_getpwnam($user))) {
- die("Failed to get passwd entry for user \"$user\"\n");
- }
- # Set the default timezone to the system's timezone.
- if (function_exists("date_default_timezone_set") and
- function_exists("date_default_timezone_get"))
- @date_default_timezone_set(@date_default_timezone_get());
- if (file_exists($pidfile)) {
- $pid = rtrim(file_get_contents($pidfile));
- if (posix_kill($pid, 0)) {
- die("Failed to create pidfile $pidfile (PID $pid is still running)\n");
- }
- trigger_error("Removing stale pidfile $pidfile", E_USER_NOTICE);
- unlink($pidfile);
- }
- # if debug ist not set open a child process
- if (!$debug) {
- $pid = pcntl_fork();
- if ($pid == -1) {
- die("Could not fork");
- } else if ($pid) {
- // We are the parent, we may exit now.
- exit(0);
- }
- }
- $pid = pcntl_fork();
- if ($pid == -1) {
- die("Could not fork again");
- } else if ($pid) {
- pcntl_signal(SIGINT, SIG_IGN);
- pcntl_signal(SIGTERM, SIG_IGN);
- // We are the parent. Write pidfile and wait until the child exists.
- if (!file_put_contents($pidfile, "$pid\n")) {
- posix_kill($pid, 15);
- die("Failed to create pidfile $pidfile");
- }
- $child = pcntl_waitpid($pid, $status);
- unlink($pidfile);
- exit;
- }
- $uid = $passwd['uid'];
- $gid = $passwd['gid'];
- if (!posix_setgid($gid) or !posix_setuid($uid)) {
- die("Failed revoke privileges to run as user \"$user\"\n");
- }
- function sig_handler($signo)
- {
- switch ($signo) {
- case SIGINT:
- case SIGTERM:
- // handle shutdown tasks
- Logger::info("Got signal $signo, exiting");
- exit(128 + $signo);
- }
- }
- function err_handler($errno, $errstr, $errfile, $errline, $errcontext)
- {
- switch ($errno) {
- case E_USER_ERROR:
- // print and exit
- Logger::error("Fatal error: $errstr in $errfile on line $errline (exiting)");
- case E_USER_WARNING:
- Logger::warn("Warning: $errstr in $errfile on line $errline");
- break;
- case E_USER_NOTICE:
- Logger::info("Notice: $errstr in $errfile on line $errline");
- break;
- default:
- Logger::warn("Unknown error type $errno: $errstr in $errfile on line $errline");
- break;
- }
- return TRUE;
- }
- /**
- * basic logger
- *
- * Example usage:
- * @code
- * Logger::init(fopen("/var/log/veryimportant.log", "a"));
- *
- * Logger::info("Small info line");
- * Logger::warn("A little warning");
- * Logger::debug("Some sweet debug information");
- * Logger::error("Houston, we've got a (serious) problem");
- * @endcode
- */
- class Logger {
- private static $instance = NULL;
- private $handle = null;
- protected function __construct($handle) {
- $this->handle = $handle;
- register_shutdown_function(array(&$this, "__destruct"));
- }
- public function __destruct() {
- if($this->handle) {
- fclose($this->handle);
- }
- return true;
- }
- public function writeLog($level, $message) {
- if($this->handle) {
- fwrite($this->handle, sprintf("%s - %s - %s\n", date('r'), $level, $message));
- }
- }
- private final function __clone() {}
- private static function getInstance() {
- if (self::$instance === NULL) {
- throw new Exception('call init before');
- }
- return self::$instance;
- }
- public static function init($output) {
- self::$instance = new self($output);
- }
- public static function info($message) {
- self::getInstance()->writeLog('INFO', $message);
- }
- public static function warn($message) {
- self::getInstance()->writeLog('WARN', $message);
- }
- public static function debug($message) {
- self::getInstance()->writeLog('DEBUG', $message);
- }
- public static function error($message) {
- self::getInstance()->writeLog('ERROR', $message);
- exit;
- }
- }
- set_error_handler("err_handler");
- pcntl_signal(SIGINT, "sig_handler");
- pcntl_signal(SIGTERM, "sig_handler");
- # Enable the signal handle callback mechanism.
- declare(ticks = 1);
- # Open the output stream which should receive all log messages.
- # if debug is set just print the messages - if not, then log to file
- Logger::init($debug ? STDOUT : fopen("/var/log/veryimportant.log", "a"));
- # program code
- # run controller from here
- # e.g. Controller::dispatch()
- while(true) {
- Logger::info("i am running");
- sleep(1);
- }
- ?>
11.724 mal gelesen