updated on Thu Jan 26 00:18:00 UTC 2012
[aur-mirror.git] / pkgdistcache / pkgdistcache-daemon
blob0819f41f6b4137648920dec3509a114e99f63cd7
1 #!/usr/bin/python2
2 # coding: utf-8
4 # pkgdistcache daemon v0.3.1
5 # by Alessio Bianchi <venator85@gmail.com>
7 # Daemon code by Chad J. Schroeder
8 # http://code.activestate.com/recipes/278731/
11 import sys
12 import os
13 import os.path
14 import subprocess
15 import string
16 import avahi
17 import dbus
18 import gobject
19 import dbus.glib
20 import SimpleHTTPServer
21 import BaseHTTPServer
22 import signal
24 avahi_service = None
26 def terminate(signum, frame):
27         avahi_service.unpublish()
28         sys.exit(0)
30 # Run a command synchronously, redirecting stdout and stderr to strings
31 def runcmd(cmd, cwd=None):
32         pipe = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
33         (stdout, stderr) = pipe.communicate()   # wait for process to terminate and return stdout and stderr
34         return {'stdout': stdout.strip(), 'stderr': stderr.strip(), 'retcode': pipe.returncode}
36 # Detach a process from the controlling terminal and run it in the background as a daemon
37 def daemonize():
38         try:
39                 pid = os.fork()
40         except OSError, e:
41                 raise Exception, "%s [%d]" % (e.strerror, e.errno)
43         if (pid == 0):  # The first child.
44                 os.setsid()
45                 try:
46                         pid = os.fork() # Fork a second child.
47                 except OSError, e:
48                         raise Exception, "%s [%d]" % (e.strerror, e.errno)
50                 if (pid != 0):  # The second child.
51                         os._exit(0)     # Exit parent (the first child) of the second child.
52         else:
53                 os._exit(0)     # Exit parent of the first child.
55         import resource         # Resource usage information.
56         maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
57         if (maxfd == resource.RLIM_INFINITY):
58                 maxfd = 1024
59         
60         # Iterate through and close all file descriptors.
61         for fd in range(0, maxfd):
62                 try:
63                         os.close(fd)
64                 except OSError: # ERROR, fd wasn't open to begin with (ignored)
65                         pass
67         # The standard I/O file descriptors are redirected to /dev/null by default.
68         os.open("/dev/null", os.O_RDWR) # standard input (0)
69         os.dup2(0, 1)                   # standard output (1)
70         os.dup2(0, 2)                   # standard error (2)
71         return(0)
73 class AvahiPublisher:
74         #Based on http://avahi.org/wiki/PythonPublishExample
75         def __init__(self, name, stype, host, port):
76                 self.name = name
77                 self.stype = stype
78                 self.domain = 'local'
79                 self.host = host
80                 self.port = port
81                 self.systemBus = dbus.SystemBus()
82                 self.server = dbus.Interface(self.systemBus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
84         def publish(self):
85                 self.group = dbus.Interface(
86                         self.systemBus.get_object(avahi.DBUS_NAME, self.server.EntryGroupNew()),
87                         avahi.DBUS_INTERFACE_ENTRY_GROUP)
89                 self.group.AddService(
90                         avahi.IF_UNSPEC,        #interface
91                         avahi.PROTO_UNSPEC,     #protocol
92                         dbus.UInt32(0),         #flags
93                         self.name, self.stype,
94                         self.domain, self.host,
95                         dbus.UInt16(self.port),
96                         avahi.string_array_to_txt_array([]))
97                 self.group.Commit()
99         def unpublish(self):
100                 self.group.Reset()
102 def main(args):
103         import optparse
104         parser = optparse.OptionParser()
105         parser.add_option("-F", "--foreground", action="store_true", dest="no_daemon", default=False,
106                               help="run pkgdistcache-daemon in foreground")
107         (options, args) = parser.parse_args()
108         if options.no_daemon == False:
109                 # fork daemon in background
110                 daemonize()
112         # load configuration file
113         conf_file = '/etc/pkgdistcache.conf'
114         if os.path.isfile(conf_file):
115                 config = eval(open(conf_file).read())
116         else:
117                 printerr("Config file " + conf_file + " not found")
118                 return 2
119         
120         port = config['port']
121         hostname = runcmd('hostname')['stdout']
122         global avahi_service
123         avahi_service = AvahiPublisher(hostname, '_pkgdistcache._tcp', '', port)
124         avahi_service.publish()
125         
126         os.chdir('/var/cache/pacman/pkg')
127         handler = SimpleHTTPServer.SimpleHTTPRequestHandler
128         httpd = BaseHTTPServer.HTTPServer(('', port), handler)
130         try:
131                 httpd.serve_forever()
132         except KeyboardInterrupt:
133                 avahi_service.unpublish()
135         return 0
137 if __name__ == '__main__':
138         signal.signal(signal.SIGTERM, terminate)
139         main(sys.argv)