# -*- coding: utf-8-*- # # This file is part of stdd, the simple time display daemon, # written by Helmut Pozimski , # licensed under the 3-clause BSD license """ Generic module to implement a daemon in python, takes care of the creation of the PID files and the usual daemonizing stuff. """ from __future__ import unicode_literals import os import sys class Daemon(object): """ Tries to implement a well behaving unix daemon in a generic way, so the code could be used in different projects. """ def __init__(self, pfile_path, pfile_name): """ Initializes the object. """ self._pfile_path = pfile_path self._pfile_name = pfile_name self._daemon = False def daemonize(self): """ Turns the calling prozess into a daemon running on it's own """ try: # Fork for the first time pid = os.fork() except OSError: sys.exit(os.EX_OSERR) else: if pid > 0: sys.exit(os.EX_OK) # Become session and group leader os.setsid() try: # Fork for the second time pid = os.fork() except OSError: sys.exit(os.EX_OSERR) else: if pid > 0: sys.exit(os.EX_OK) # Change cwd to / to avoid interfering with other mounted file systems os.chdir("/") # Reset the umask os.umask(0o22) # Close possibly open file descriptors os.close(0) os.close(1) os.close(2) # And redirect them to /dev/null os.open("/dev/null", 0) os.open("/dev/null", 1) os.open("/dev/null", 2) self._daemon = True def drop_privileges(self, user, group): """ If the daemon is running as root user, drop privileges and continue running as the defined unprivileged user. """ pid_file_path = os.path.join(self._pfile_path, self._pfile_name) passwd_file = open("/etc/passwd", "r") group_file = open("/etc/group", "r") uid = "" gid = "" for line in passwd_file: if user in line: uid = line.split(":")[2] break for line in group_file: if group in line.split(":")[0]: gid = line.split(":")[2] break passwd_file.close() group_file.close() if os.getuid() == 0: os.chown(pid_file_path, int(uid), int(gid)) os.setgid(int(gid)) os.setuid(int(uid)) @staticmethod def set_name(name, cmdline): """ Sets the name of the process shown visible in ps and top, this allows to make your daemon look more like a standalone program instead of a python script. """ try: # First check if prctl is available, otherwise this function # does nothing import prctl except ImportError: return False else: prctl.set_name(name) prctl.set_proctitle(cmdline) return True def start(self): """ Performs the operations needed to "start" the daemon """ if self._daemon is True: if os.access(self._pfile_path, os.F_OK & os.W_OK): pidfile = open(os.path.join(self._pfile_path, self._pfile_name), "w") pidfile.write(str(os.getpid()) + "\n") pidfile.close() return True else: return False else: return False def stop(self): """ Performs the operations needed to stop the daemon """ if self._daemon is True: try: os.remove(os.path.join(self._pfile_path, self._pfile_name)) except OSError: return False else: return True else: return True