180 lines
6.1 KiB
Python
Executable file
180 lines
6.1 KiB
Python
Executable file
#!/usr/bin/env python2.4
|
|
#
|
|
# The daemon script to run the CryptoBox webserver.
|
|
#
|
|
# run the script with "--help" to see all possible paramters
|
|
#
|
|
|
|
import os, sys
|
|
import cryptobox.web.sites
|
|
from cryptobox.core.exceptions import *
|
|
from optparse import OptionParser
|
|
|
|
try:
|
|
import cherrypy
|
|
except:
|
|
print "Could not import the cherrypy module! Try 'apt-get install python-cherrypy'."
|
|
sys.exit(1)
|
|
|
|
|
|
# TODO: change this for the release version
|
|
SERVER_ENVIRONMENT = "development"
|
|
|
|
class CryptoBoxWebserver:
|
|
'''this class starts the cherryp webserver and serves the single sites'''
|
|
|
|
def __init__(self, opts):
|
|
## check conffile
|
|
if not os.access(opts.conffile, os.R_OK) or not os.path.isfile(opts.conffile):
|
|
sys.stderr.write("Error: could not read configuration file (%s)\n" % opts.conffile)
|
|
sys.exit(1)
|
|
## store the absolute path as we will chdir later (for daemons)
|
|
self.conffile = os.path.realpath(opts.conffile)
|
|
## initialize site class
|
|
try:
|
|
cherrypy.root = cryptobox.web.sites.WebInterfaceSites(self.conffile)
|
|
except (CBConfigError,CBEnvironmentError), errMsg:
|
|
sys.stderr.write("Error: the CryptoBox is misconfigured - please fix it!\n")
|
|
sys.stderr.write("%s\n" % str(errMsg))
|
|
sys.exit(1)
|
|
#expose static content:
|
|
#I currently have no idea how to cleanly extract the stylesheet path from
|
|
#the config object without an extra cryptobox.core.main.CryptoBoxProps instance.
|
|
#perhaps put config handling into a separate class in CryptoBox.py?
|
|
#
|
|
# the following manual mapping is necessary, as we may not use relative
|
|
# paths in the config file
|
|
cherrypy.config.update({
|
|
"global": {
|
|
"server.socket_port" : int(opts.port),
|
|
"server.socket_host" : opts.host,
|
|
"server.log_to_screen" : not opts.background and opts.verbose,
|
|
"server.log_tracebacks" : opts.verbose,
|
|
"server.environment": SERVER_ENVIRONMENT,
|
|
"server.log_file" : opts.logfile },
|
|
"/cryptobox-misc": {
|
|
"staticFilter.on" : True,
|
|
"staticFilter.dir": os.path.realpath(opts.datadir)}
|
|
})
|
|
|
|
def start(self):
|
|
cherrypy.server.start()
|
|
|
|
|
|
def fork_to_background():
|
|
## this is just copy'n'pasted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/278731
|
|
## check the original for exhaustive comments
|
|
try:
|
|
pid = os.fork()
|
|
except OSError, errMsg:
|
|
sys.stderr.write("Error: failed to fork cryptobox daemon process!\n")
|
|
sys.stderr.write("%s\n" % errMsg)
|
|
sys.exit(1)
|
|
if pid == 0: # the first child
|
|
os.setsid()
|
|
try:
|
|
pid = os.fork()
|
|
except OSError, errMsg:
|
|
sys.stderr.write("Error: failed to fork second cryptobox daemon process!\n")
|
|
sys.stderr.write("%s\n" % errMsg)
|
|
sys.exit(1)
|
|
if pid == 0: # the second child
|
|
## we do not change the directory - otherwise there seems to be a race condition with the python interpreter loading this script file
|
|
#os.chdir(os.path.sep)
|
|
os.umask(0)
|
|
else:
|
|
os._exit(0)
|
|
else:
|
|
os._exit(0)
|
|
|
|
|
|
def close_open_files():
|
|
"""this is only necessary if we want to go into background"""
|
|
import resource # Resource usage information.
|
|
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
|
if (maxfd == resource.RLIM_INFINITY):
|
|
maxfd = 1024
|
|
for fd in range(0, maxfd):
|
|
try:
|
|
os.close(fd)
|
|
except OSError: # ERROR, fd wasn't open to begin with (ignored)
|
|
pass
|
|
os.open(os.devnull, os.O_RDWR) # standard input (0)
|
|
os.dup2(0, 1) # standard output (1)
|
|
os.dup2(0, 2) # standard error (2)
|
|
|
|
|
|
def write_pid_file(pid_file):
|
|
try:
|
|
pidf = open(pid_file,"w")
|
|
pidf.write(str(os.getpid()))
|
|
pidf.close()
|
|
except (IOError, OSError), errMsg:
|
|
sys.stderr.write("Warning: failed to write pid file (%s): %s\n" % (pid_file, errMsg))
|
|
## it is just a warning - no need to break
|
|
|
|
|
|
def parseOptions():
|
|
version = "%prog" + cryptobox.core.main.VERSION
|
|
parser = OptionParser(version=version)
|
|
parser.set_defaults(conffile="/etc/cryptobox/webserver.conf",
|
|
pidfile="/var/run/cryptobox/webserver.pid",
|
|
background=False,
|
|
datadir="/usr/share/cryptobox/www-data",
|
|
logfile="/var/log/cryptobox/webserver.log",
|
|
port="8080",
|
|
host="",
|
|
verbose=True)
|
|
parser.add_option("-c", "--config", dest="conffile",
|
|
help="read configuration from FILE", metavar="FILE")
|
|
parser.add_option("","--pidfile", dest="pidfile",
|
|
help="write process id to FILE", metavar="FILE")
|
|
parser.add_option("-B","", dest="background", action="store_true",
|
|
help="run webserver in background (as daemon)")
|
|
parser.add_option("-q","", dest="verbose", action="store_false",
|
|
help="output only errors")
|
|
parser.add_option("","--datadir", dest="datadir", metavar="DIR",
|
|
help="set data directory to DIR")
|
|
parser.add_option("-p","--port", dest="port", metavar="PORT",
|
|
help="listen on PORT")
|
|
parser.add_option("-l","--logfile", dest="logfile", metavar="FILE",
|
|
help="write webserver log to FILE")
|
|
parser.add_option("","--host", dest="host", metavar="HOST",
|
|
help="attach to HOST")
|
|
(options, args) = parser.parse_args()
|
|
## we do not expect any remaining arguments
|
|
if len(args) != 0:
|
|
parser.error("unknown argument: %s" % str(args[0]))
|
|
if not os.path.isdir(options.datadir) or not os.access(options.datadir,os.X_OK):
|
|
parser.error("could not access the data directory (%s)" % options.datadir)
|
|
try:
|
|
if (int(options.port) < 0) or (int(options.port) > 65535):
|
|
parser.error("invalid port number: %s" % str(options.port))
|
|
except ValueError:
|
|
parser.error("invalid port specified (%s) - it must be a number" % (options.port))
|
|
return options
|
|
|
|
|
|
if __name__ == "__main__":
|
|
## process arguments
|
|
options = parseOptions()
|
|
## run the webserver as a daemon process
|
|
if options.background: fork_to_background()
|
|
## close open files to allow background execution
|
|
if options.background: close_open_files()
|
|
## write pid file
|
|
write_pid_file(options.pidfile)
|
|
## TODO: if we close the open files _after_ initialization, then we also close
|
|
## the log out - we have to figure something out here ...
|
|
## initialize the webserver class (before forking to get some error messages)
|
|
cbw = CryptoBoxWebserver(options)
|
|
## start the webserver
|
|
try:
|
|
cbw.start()
|
|
except CBError, errMsg:
|
|
sys.stderr.write("Failed to start the CryptoBox webserver!\n")
|
|
sys.stderr.write("%s\n" % str(errMsg))
|
|
sys.stderr.write("Check the log file for details.\n")
|
|
sys.exit(1)
|
|
sys.exit(0)
|
|
|