cc1  v2.1
CC1 source code docs
 All Classes Namespaces Files Functions Variables Pages
daemon.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # @COPYRIGHT_begin
3 #
4 # Copyright [2010-2014] Institute of Nuclear Physics PAN, Krakow, Poland
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 # @COPYRIGHT_end
19 
20 #!/usr/bin/env python
21 
22 import sys
23 import os
24 import time
25 import atexit
26 from signal import SIGTERM
27 
28 
29 ##
30 #
31 # A generic daemon class.
32 #
33 # Usage: subclass the Daemon class and override the run() method
34 #
35 class Daemon:
36  def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
37  self.stdin = stdin
38  self.stdout = stdout
39  self.stderr = stderr
40  self.pidfile = pidfile
41 
42  ##
43  #
44  # do the UNIX double-fork magic, see Stevens' "Advanced
45  # Programming in the UNIX Environment" for details (ISBN 0201563177)
46  # http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
47  #
48  def daemonize(self):
49  try:
50  pid = os.fork()
51  if pid > 0:
52  # exit first parent
53  sys.exit(0)
54  except OSError, e:
55  sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
56  sys.exit(1)
57 
58  # decouple from parent environment
59  os.chdir("/")
60  os.setsid()
61  os.umask(0)
62 
63  # do second fork
64  try:
65  pid = os.fork()
66  if pid > 0:
67  # exit from second parent
68  sys.exit(0)
69  except OSError, e:
70  sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
71  sys.exit(1)
72 
73  # redirect standard file descriptors
74  sys.stdout.flush()
75  sys.stderr.flush()
76  si = file(self.stdin, 'r')
77  so = file(self.stdout, 'a+')
78  se = file(self.stderr, 'a+', 0)
79  os.dup2(si.fileno(), sys.stdin.fileno())
80  os.dup2(so.fileno(), sys.stdout.fileno())
81  os.dup2(se.fileno(), sys.stderr.fileno())
82 
83  # write pidfile
84  atexit.register(self.delpid)
85  pid = str(os.getpid())
86  file(self.pidfile, 'w+').write("%s\n" % pid)
87 
88  def delpid(self):
89  os.remove(self.pidfile)
90 
91  ##
92  #
93  # Start the daemon
94  #
95  def start(self):
96  # Check for a pidfile to see if the daemon already runs
97  try:
98  pf = file(self.pidfile, 'r')
99  pid = int(pf.read().strip())
100  pf.close()
101  except IOError:
102  pid = None
103 
104  if pid:
105  message = "pidfile %s already exist. Daemon already running?\n"
106  sys.stderr.write(message % self.pidfile)
107  sys.exit(1)
108 
109  # Start the daemon
110  self.daemonize()
111  self.run()
112 
113  ##
114  #
115  # Stop the daemon
116  #
117  def stop(self):
118  # Get the pid from the pidfile
119  try:
120  pf = file(self.pidfile, 'r')
121  pid = int(pf.read().strip())
122  pf.close()
123  except IOError:
124  pid = None
125 
126  if not pid:
127  message = "pidfile %s does not exist. Daemon not running?\n"
128  sys.stderr.write(message % self.pidfile)
129  return # not an error in a restart
130 
131  # Try killing the daemon process
132  try:
133  while 1:
134  os.kill(pid, SIGTERM)
135  time.sleep(0.1)
136  except OSError, err:
137  err = str(err)
138  if err.find("No such process") > 0:
139  if os.path.exists(self.pidfile):
140  os.remove(self.pidfile)
141  else:
142  print str(err)
143  sys.exit(1)
144 
145  ##
146  #
147  # Restart the daemon
148  #
149  def restart(self):
150  self.stop()
151  self.start()
152 
153  ##
154  #
155  # You should override this method when you subclass Daemon. It will be called after the process has been
156  # daemonized by start() or restart().
157  #
158  def run(self):
159