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