diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..93cd63a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: python +python: + - "2.7" + - "3.3" + +install: + - "python setup.py install" \ No newline at end of file diff --git a/yapdi.py b/yapdi.py index c9db7bb..7c0e064 100644 --- a/yapdi.py +++ b/yapdi.py @@ -4,11 +4,13 @@ # YapDi - Yet another python Daemon implementation # Author Kasun Herath # +# Python 3 compatibility by Anton Osten ''' from signal import SIGTERM import sys, atexit, os, pwd import time +from warnings import warn OPERATION_SUCCESSFUL = 0 OPERATION_FAILED = 1 @@ -16,6 +18,16 @@ INSTANCE_NOT_RUNNING = 3 SET_USER_FAILED = 4 +# python 2 and 3 compatibility +pyversion = sys.version_info[0] + +if pyversion is 2: + no_file_error = IOError + no_process_error = OSError +else: + no_file_error = FileNotFoundError + no_process_error = ProcessLookupError + class Daemon: def __init__(self, pidfile=None, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): self.stdin = stdin @@ -34,13 +46,14 @@ def __init__(self, pidfile=None, stdin='/dev/null', stdout='/dev/null', stderr=' def daemonize(self): ''' Daemonize the current process and return ''' if self.status(): + warn('YapDi: instance is already running', RuntimeWarning) return INSTANCE_ALREADY_RUNNING try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) - except OSError, e: + except OSError as e: return OPERATION_FAILED # decouple from parent environment @@ -53,15 +66,15 @@ def daemonize(self): if pid > 0: # exit from second parent sys.exit(0) - except OSError, e: + except OSError as e: return OPERATION_FAILED # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() - si = file(self.stdin, 'r') - so = file(self.stdout, 'a+') - se = file(self.stderr, 'a+', 0) + si = open(self.stdin) + so = open(self.stdout, 'a+') + se = open(self.stderr, 'a+') os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) @@ -69,16 +82,18 @@ def daemonize(self): # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) - file(self.pidfile,'w+').write("%s\n" % pid) + + with open(self.pidfile, 'w+') as file: + file.write("%s\n" % pid) # If daemon user is set change current user to self.daemon_user if self.daemon_user: try: uid = pwd.getpwnam(self.daemon_user)[2] os.setuid(uid) - except NameError, e: + except NameError as e: return SET_USER_FAILED - except OSError, e: + except OSError as e: return SET_USER_FAILED return OPERATION_SUCCESSFUL @@ -92,14 +107,14 @@ def kill(self): if not pid: return INSTANCE_NOT_RUNNING - # Try killing the daemon process + # Try killing the daemon process try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) - except OSError, err: + except no_process_error as err: err = str(err) - if err.find("No such process") > 0: + if "No such process" in err: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: @@ -117,10 +132,17 @@ def restart(self): def status(self): ''' check whether an instance is already running. If running return pid or else False ''' try: - pf = file(self.pidfile,'r') + pf = open(self.pidfile) pid = int(pf.read().strip()) - pf.close() - except IOError: + + # check if it is actually running or even exists + try: + os.kill(pid, 0) + except no_process_error: + os.remove(self.pidfile) + pid = None + + except no_file_error: pid = None return pid