[#] Piszemy daemona w języku Python

( Ostatnio zmieniony pon., 13/04/2009 - 23:14 )
 

daemon.py

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys, os, time, atexit
from signal import SIGTERM

from daemon_misc import RenameProcess
RenameProcess('MojDaemon')

class Daemon:
        """
        Standardowa klasa daemona.

        Użycie: Nadpisz metodę run() klasy Daemon w podklasie
        """
        def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
                self.stdin = stdin
                self.stdout = stdout
                self.stderr = stderr
                self.pidfile = pidfile

        def daemonize(self):
                """
                no to robimy fork
                """
                try:
                        pid = os.fork()
                        if pid > 0:
                                # wyjście z pierwszego rodzica
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("Błąd fork #1: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # odłączamy środowisko rodzica
                os.chdir("/")
                os.setsid()
                os.umask(0)

                # drugi fork
                try:
                        pid = os.fork()
                        if pid > 0:
                                # wyjście z drugiego rodzica
                                print "Daemon PID %d" % pid
                                sys.exit(0)
                except OSError, e:
                        sys.stderr.write("Błąd fork #2: %d (%s)\n" % (e.errno, e.strerror))
                        sys.exit(1)

                # przekierowanie standardowych deskryptorów pliku
                sys.stdout.flush()
                sys.stderr.flush()
                si = file(self.stdin, 'r')
                so = file(self.stdout, 'a+')
                se = file(self.stderr, 'a+', 0)
                os.dup2(si.fileno(), sys.stdin.fileno())
                os.dup2(so.fileno(), sys.stdout.fileno())
                os.dup2(se.fileno(), sys.stderr.fileno())

                # tworzymy plik pid
                atexit.register(self.delpid)
                pid = str(os.getpid())
                file(self.pidfile,'w+').write("%s\n" % pid)


        def delpid(self):
                os.remove(self.pidfile)


        def status(self):
                 # Sprawdzenie pliku pid
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                        print "Daemon działa z PID = %d" % pid
                        return True
                except IOError:
                        pid = None
                        print 'Daemon nie działa'
                        return False


        def start(self):
                """
                Start daemona
                """
                # Sprawdzenie pliku pid, czy przypadkiem nie jest już uruchomiony
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if pid:
                        message = "Plik pid %s już istnieje. Daemon cały czas działa?\n"
                        sys.stderr.write(message % self.pidfile)
                        sys.exit(1)

                # Start daemona
                self.daemonize()
                self.run()


        def stop(self):
                """
                Stop daemona
                """
                # Pobieramy id procesu z pliku pid
                try:
                        pf = file(self.pidfile,'r')
                        pid = int(pf.read().strip())
                        pf.close()
                except IOError:
                        pid = None

                if not pid:
                        message = "Plik pid %s nie istnieje. Daemon nie działa?\n"
                        sys.stderr.write(message % self.pidfile)
                        return # to nie błąd podczas restartu

                # Próbujemy zabić proces daemona
                try:
                        while 1:
                                os.kill(pid, SIGTERM)
                                time.sleep(0.1)
                except OSError, err:
                        err = str(err)
                        if err.find("No such process") > 0:
                                if os.path.exists(self.pidfile):
                                        os.remove(self.pidfile)
                        else:
                                print str(err)
                                sys.exit(1)

        def restart(self):
                """
                Restart daemona
                """
                self.stop()
                self.start()

        def run(self):
                """
                Powinieneś nadpisać tą metodę w podklasie klasy Daemon.
                Będzie ona wywołana po przejściu procesu w tryb daemona z uzyciem start() i restart().
                """

daemon_misc.py

#!/usr/bin/env python
#-*- coding:utf-8 -*-

def RenameProcess(newname, debug = False):
        errors = []
        # dla ps
        try:
                import procname
                procname.setprocname(newname)
        except:
                errors.append("Błąd użycia modułu procname")
        # dla pkill
        try:
                import ctypes
                # Linux
                libc = ctypes.CDLL('libc.so.6')
                libc.prctl(15, newname, 0, 0, 0)
        except:
                errors.append("Błąd użycia Linux libc")
        try:
                import dl
                # FreeBSD
                libc = dl.open('/lib/libc.so.6')
                libc.call('setproctitle', newname + '\0')
                renamed = True
        except:
                errors.append("Błąd użycia metody FreeBSD")
        if debug and errors:
                print "Błędy które wystąpiły podczas próby zmiany nazwy procesu:"
                for i in errors:
                        print i

daemon_example.py

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys, time
from daemon import Daemon

pid_path = '/tmp/daemon.pid'
log_path = '/tmp/daemon.log'

class MojDaemon(Daemon):
        def run(self):
                f = open(log_path, "w")
                while True:
                        f.write('%s\n' % time.ctime(time.time()))
                        f.flush()
                        time.sleep(5)


if __name__ == "__main__":
        daemon = MojDaemon(pid_path)
        if len(sys.argv) == 2:
                if 'start' == sys.argv[1]:
                        daemon.start()
                elif 'stop' == sys.argv[1]:
                        daemon.stop()
                elif 'restart' == sys.argv[1]:
                        daemon.restart()
                elif 'status' == sys.argv[1]:
                        daemon.status()
                else:
                        print "Nieznany parametr"
                        sys.exit(2)
                sys.exit(0)
        else:
                print "użycie: %s start|stop|restart|status" % sys.argv[0]
                sys.exit(2)
5
Twoja ocena: Brak Średnio: 5 (3 głosy)