Set a better default ciphers list if none was specified.
[pound.git] / z2_2_5_1.py
1 ##############################################################################
2 #
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE
11
12 ##############################################################################
13 """Zope 2 ZServer start-up file
14
15 Usage: %(program)s [options] [environment settings]
16
17 Options:
18
19   -h
20
21     Output this text.
22
23   -z path
24
25     The location of the Zope installation.
26     The default is the location of this script, %(here)s.
27
28   -Z path
29
30     Unix only! This option is ignored on windows.
31
32     If this option is specified, a separate managemnt process will
33     be created that restarts Zope after a shutdown (or crash).
34     The path must point to a pid file that the process will record its
35     process id in. The path may be relative, in which case it will be
36     relative to the Zope location.
37
38     To prevent use of a separate management process, provide an
39     empty string: -Z ''
40
41   -t n
42
43     The number of threads to use, if ZODB3 is used. The default is
44     %(NUMBER_OF_THREADS)s.
45
46   -i n
47
48     Set the interpreter check interval. This integer value
49     determines how often the interpreter checks for periodic things
50     such as thread switches and signal handlers. The Zope default
51     is 120, but you may want to experiment with other values that
52     may increase performance in your particular environment.
53
54   -D
55
56     Run in Zope debug mode.  This causes the Zope process not to
57     detach from the controlling terminal, and is equivalent to
58     supplying the environment variable setting Z_DEBUG_MODE=1
59
60   -a ipaddress
61
62     The IP address to listen on.  If this is an empty string
63     (e.g. -a ''), then all addresses on the machine are used. The
64     default is %(IP_ADDRESS)s.
65
66   -d ipaddress
67
68     IP address of your DNS server. If this is an empty string
69     (e.g. -d ''), then IP addresses will not be logged. If you have
70     DNS service on your local machine then you can set this to
71     127.0.0.1.  The default is: %(DNS_IP)s.
72     
73   -u username or uid number
74   
75     The username to run ZServer as. You may want to run ZServer as 'nobody'
76     or some other user with limited resouces. The only works under Unix, and
77     if ZServer is started by root. The default is: %(UID)s
78
79   -P [ipaddress:]number
80
81     Set the web, ftp and monitor port numbers simultaneously
82     as offsets from the number.  The web port number will be number+80.
83     The FTP port number will be number+21.  The monitor port number will
84     be number+99.
85
86     The number can be preeceeded by an ip address follwed by a colon
87     to specify an address to listen on. This allows different servers
88     to listen on different addresses.
89
90     Multiple -P options can be provided to run multiple sets of servers.
91     
92   -w port
93   
94     The Web server (HTTP) port.  This defaults to %(HTTP_PORT)s. The
95     standard port for HTTP services is 80.  If this is a dash
96     (e.g. -w -), then HTTP is disabled.
97
98     The number can be preeceeded by an ip address follwed by a colon
99     to specify an address to listen on. This allows different servers
100     to listen on different addresses.
101
102     Multiple -w options can be provided to run multiple servers.
103
104   -y port
105   
106     The encrypted Web server (HTTPS) port.  This defaults to %(HTTPS_PORT)s.
107     The standard port for HTTP services is 443.  If this is a dash
108     (e.g. -y -), then HTTPS is disabled.
109
110     The number can be preeceeded by an ip address follwed by a colon
111     to specify an address to listen on. This allows different servers
112     to listen on different addresses.
113
114     Multiple -y options can be provided to run multiple servers.
115
116   -W port
117   
118     The "WebDAV source" port.  If this is a dash (e.g. -W -), then
119     "WebDAV source" is disabled.  The default is disabled.  Note that
120     this feature is a workaround for the lack of "source-link" support
121     in standard WebDAV clients.
122
123     The port can be preeceeded by an ip address follwed by a colon
124     to specify an address to listen on. This allows different servers
125     to listen on different addresses.
126
127     Multiple -W options can be provided to run multiple servers.
128
129   -f port
130   
131     The FTP port.  If this is a dash (e.g. -f -), then FTP
132     is disabled.  The standard port for FTP services is 21.  The
133     default is %(FTP_PORT)s.
134
135     The port can be preeceeded by an ip address follwed by a colon
136     to specify an address to listen on. This allows different servers
137     to listen on different addresses.
138
139     Multiple -f options can be provided to run multiple servers.
140
141   -p path
142
143     Path to the PCGI resource file.  The default value is
144     %(PCGI_FILE)s, relative to the Zope location.  If this is a dash
145     (-p -) or the file does not exist, then PCGI is disabled.
146
147   -F path_or_port
148
149     Either a port number (for inet sockets) or a path name (for unix
150     domain sockets) for the FastCGI Server.  If the flag and value are
151     not specified then the FastCGI Server is disabled.
152
153   -m port
154   
155     The secure monitor server port. If this is a dash
156     (-m -), then the monitor server is disabled. The monitor server
157     allows interactive Python style access to a running ZServer. To
158     access the server see medusa/monitor_client.py or
159     medusa/monitor_client_win32.py. The monitor server password is the
160     same as the Zope emergency user password set in the 'access'
161     file. The default is to not start up a monitor server.
162
163     The port can be preeceeded by an ip address follwed by a colon
164     to specify an address to listen on. This allows different servers
165     to listen on different addresses.
166
167     Multiple -m options can be provided to run multiple servers.
168
169   -l path
170
171     Path to the ZServer log file. If this is a relative path then the
172     log file will be written to the 'var' directory. The default is
173     %(LOG_FILE)s. 
174
175   -r
176     
177     Run ZServer is read-only mode. ZServer won't write anything to disk.
178     No log files, no pid files, nothing. This means that you can't do a
179     lot of stuff like use PCGI, and zdaemon. ZServer will log hits to
180     STDOUT and zLOG will log to STDERR.
181
182   -L
183   
184     Enable locale (internationalization) support. The value passed for
185     this option should be the name of the locale to be used (see your
186     operating system documentation for locale information specific to
187     your system). If an empty string is passed for this option (-L ''),
188     Zope will set the locale to the user's default setting (typically
189     specified in the $LANG environment variable). If your Python
190     installation does not support the locale module, the requested
191     locale is not supported by your system or an empty string was
192     passed but no default locale can be found, an error will be raised
193     and Zope will not start.
194
195   -X
196
197     Disable servers. This might be used to effectively disable all
198     default server settings or previous server settings in the option
199     list before providing new settings. For example to provide just a
200     web server:
201
202       %(program)s -X -w80
203       
204   -M file
205
206     Save detailed logging information to the given file.
207     This log includes separate entries for:
208
209       - The start of a request,
210       - The start of processing the request in an application thread,
211       - The start of response output, and
212       - The end of the request.
213
214 Environment settings are of the form: NAME=VALUE.
215
216 Note: you *must* use Python 2.1 or later!
217 """
218
219
220 # This is required path hackery for the win32 binary distribution
221 # that ensures that the bundled python libraries are used. In a
222 # win32 binary distribution, the installer will have replaced the
223 # marker string with the actual software home. If that has not
224 # happened, then the path munging code is skipped.
225 swhome=r'INSERT_SOFTWARE_HOME'
226 if swhome != 'INSERT_SOFTWARE_HOME':
227     import sys
228     sys.path.insert(0, '%s/lib/python' % swhome)
229     sys.path.insert(1, '%s/bin/lib' % swhome)
230     sys.path.insert(2, '%s/bin/lib/plat-win' % swhome)
231     sys.path.insert(3, '%s/bin/lib/win32' % swhome)
232     sys.path.insert(4, '%s/bin/lib/win32/lib' % swhome)
233     sys.path.insert(5, '%s' % swhome)
234
235
236 import os, sys, getopt, string, codecs
237 # workaround to allow unicode encoding conversions in DTML
238 dummy = codecs.lookup('iso-8859-1')
239
240 sys.setcheckinterval(120)
241
242
243 program=sys.argv[0]
244 here=os.path.join(os.getcwd(), os.path.split(program)[0])
245 Zpid=''
246
247 ########################################################################
248 # Configuration section
249
250 ## General configuration options
251 ##
252
253 # If you want run as a daemon, then uncomment the line below:
254 if sys.platform=='win32': Zpid=''
255 else: Zpid='zProcessManager.pid'
256
257 # This is the IP address of the network interface you want your servers to
258 # be visible from.  This can be changed to '' to listen on all interfaces.
259 IP_ADDRESS=''
260
261 # IP address of your DNS server. Set to '' if you do not want to resolve
262 # IP addresses. If you have DNS service on your local machine then you can
263 # set this to '127.0.0.1'
264 DNS_IP=''
265
266 # User id to run ZServer as. Note that this only works under Unix, and if
267 # ZServer is started by root.
268 UID='nobody'
269
270 # Log file location. If this is a relative path, then it is joined the
271 # the 'var' directory.
272 LOG_FILE='Z2.log'
273
274 ## HTTP configuration
275 ##
276
277 # Port for HTTP Server. The standard port for HTTP services is 80.
278 HTTP_PORT=8080
279
280 # HTTP enivornment settings.
281 HTTP_ENV={}
282
283 # Port for HTTPS Server. The standard port for HTTPS services is 443.
284 HTTPS_PORT=8443
285
286 # HTTPS enivornment settings.
287 HTTPS_ENV={}
288
289 # Port for the special "WebDAV source view" HTTP handler.  There is no
290 # standard port for this handler, which is disabled by default.
291 WEBDAV_SOURCE_PORT=[]
292
293 ## FTP configuration
294
295 # Port for the FTP Server. The standard port for FTP services is 21.
296 FTP_PORT=8021
297
298 ## PCGI configuration
299
300 # You can configure the PCGI server manually, or have it read its
301 # configuration information from a PCGI info file.
302 PCGI_FILE='Zope.cgi'
303
304 ## Monitor configuration
305 MONITOR_PORT=0
306
307 # Module to be published, which must be Main or Zope
308 MODULE='Zope'
309
310 # The size of the thread pool, if ZODB3 is used.
311 NUMBER_OF_THREADS=4
312
313
314 # Localization support
315 LOCALE_ID=None
316
317
318
319 # Socket path or port for the FastCGI Server
320 FCGI_PORT=None
321
322 # Detailed log file
323 DETAILED_LOG_FILE=''
324
325 #
326 ########################################################################
327
328 ########################################################################
329 # Handle command-line arguments:
330
331 def server_info(old, v, offset=0):
332     # interpret v as a port or address/port and get new value
333     if v == '-': v=''
334     l=string.find(v, ':')
335     if l >= 0:
336         a=v[:l]
337         v=v[l+1:]
338     else:
339         a=IP_ADDRESS
340
341     if not v: return v
342         
343     try: 
344         v=string.atoi(v)
345         if v < 0: raise 'Invalid port', v
346         v=v+offset
347     except: raise 'Invalid port', v
348
349     if type(old) is type(0): old=[(a,v)]
350     else: old.append((a,v))
351
352     return old    
353     
354
355 try:
356     if string.split(sys.version)[0] < '2.1':
357         raise 'Invalid python version', string.split(sys.version)[0]
358
359     opts, args = getopt.getopt(sys.argv[1:],
360                                'hz:Z:t:i:a:d:u:w:y:W:f:p:m:Sl:2DP:rF:L:XM:')
361
362     DEBUG=0
363     READ_ONLY=0
364     
365     # Get environment variables
366     for a in args:
367         if string.find(a,'='):
368             a=string.split(a,'=')
369             o=a[0]
370             v=string.join(a[1:],'=')
371             if o: 
372               os.environ[o]=v
373               HTTP_ENV[o]=v
374               HTTPS_ENV[o]=v
375         else:
376             raise 'Invalid argument', a
377
378     for o, v in opts:
379         if o=='-z': here=v
380         elif o=='-Z':
381             if v=='-': v=''
382             Zpid=v
383         elif o=='-r': READ_ONLY=1
384         elif o=='-t':
385             try: v=string.atoi(v)
386             except: raise 'Invalid number of threads', v
387             NUMBER_OF_THREADS=v
388
389         elif o=='-i':
390             try: v=string.atoi(v)
391             except: raise 'Invalid value for -i option', v
392             sys.setcheckinterval(v)
393
394         elif o=='-a': IP_ADDRESS=v
395         elif o=='-d':
396             if v=='-': v=''
397             DNS_IP=v
398         elif o=='-u': UID=v
399         elif o=='-D':
400             os.environ['Z_DEBUG_MODE']='1'
401             DEBUG=1
402         elif o=='-S': sys.ZMANAGED=1
403         elif o=='-X':
404             MONITOR_PORT=HTTP_PORT=HTTPS_PORT=FTP_PORT=FCGI_PORT=0
405             PCGI_FILE=''
406         elif o=='-m':
407             MONITOR_PORT=server_info(MONITOR_PORT, v)
408         elif o=='-w':
409             HTTP_PORT=server_info(HTTP_PORT, v)
410         elif o=='-y':
411             HTTPS_PORT=server_info(HTTPS_PORT, v)
412         elif o=='-W':
413             WEBDAV_SOURCE_PORT=server_info(WEBDAV_SOURCE_PORT, v)
414         elif o=='-f':
415             FTP_PORT=server_info(FTP_PORT, v)
416         elif o=='-P':
417             HTTP_PORT=server_info(HTTP_PORT, v, 80)
418             HTTPS_PORT=server_info(HTTPS_PORT, v, 443)
419             FTP_PORT=server_info(FTP_PORT, v, 21)
420
421         elif o=='-p':
422             if v=='-': v=''
423             PCGI_FILE=v
424         elif o=='-h':
425             print __doc__ % vars()
426             sys.exit(0)
427         elif o=='-2': MODULE='Main'
428         elif o=='-l': LOG_FILE=v
429         elif o=='-L':
430             if v: LOCALE_ID=v
431             else: LOCALE_ID=''
432         elif o=='-F':
433             if v=='-': v=''
434             FCGI_PORT=v
435         elif o=='-M': DETAILED_LOG_FILE=v
436
437 except SystemExit: sys.exit(0)
438 except:
439     print __doc__ % vars()
440     print
441     print 'Error:'
442     print "%s: %s" % (sys.exc_type, sys.exc_value)
443     sys.exit(1)
444
445 if sys.platform=='win32': Zpid=''
446
447 #
448 ########################################################################
449
450 ########################################################################
451 # OK, let's get going!
452
453 # Jigger path:
454 sys.path=[os.path.join(here,'lib','python'),here
455           ]+filter(None, sys.path)
456
457
458
459 # Try to set the locale if specified on the command
460 # line. If the locale module is not available or the
461 # requested locale is not supported by the local
462 # machine, raise an error so that the user is made
463 # aware of the problem.
464
465 def set_locale(val):
466     try:
467         import locale
468     except:
469         raise SystemExit, (
470             'The locale module could not be imported.\n'
471             'To use localization options, you must ensure\n'
472             'that the locale module is compiled into your\n'
473             'Python installation.'
474             )
475     try:
476         locale.setlocale(locale.LC_ALL, val)
477     except:
478         raise SystemExit, (
479             'The specified locale is not supported by your system.\n'
480             'See your operating system documentation for more\n'
481             'information on locale support.'
482             )
483 if LOCALE_ID is not None:
484     set_locale(LOCALE_ID)
485
486
487 # from this point forward we can use the zope logger
488
489 # Import ZServer before we open the database or get at interesting
490 # application code so that ZServer's asyncore gets to be the
491 # official one. Also gets SOFTWARE_HOME, INSTANCE_HOME, and CLIENT_HOME
492 import ZServer
493
494 if Zpid and not READ_ONLY:
495     import zdaemon, App.FindHomes, posix
496     sys.ZMANAGED=1
497     
498     zdaemon.run(sys.argv, os.path.join(CLIENT_HOME, Zpid))
499
500 try:
501     # Import logging support
502     import zLOG
503     import ZLogger
504
505     if READ_ONLY:
506         if hasattr(zLOG, '_set_stupid_dest'):
507             zLOG._set_stupid_dest(sys.stderr)
508         else:
509             zLOG._stupid_dest = sys.stderr
510     else:
511         zLOG.log_write = ZLogger.ZLogger.log_write
512
513     if DETAILED_LOG_FILE:
514         from ZServer import DebugLogger
515         logfile=os.path.join(CLIENT_HOME, DETAILED_LOG_FILE)
516         DebugLogger.log=DebugLogger.DebugLogger(logfile).log
517
518     # Import Zope (or Main)
519     exec "import "+MODULE in {}
520
521     # Location of the ZServer log file. This file logs all ZServer activity.
522     # You may wish to create different logs for different servers. See
523     # medusa/logger.py for more information.
524     if not os.path.isabs(LOG_FILE):
525         LOG_PATH=os.path.join(CLIENT_HOME, LOG_FILE)
526     else:
527         LOG_PATH=LOG_FILE
528
529     # Location of the ZServer pid file. When ZServer starts up it will write
530     # its PID to this file.
531     PID_FILE=os.path.join(CLIENT_HOME, 'Z2.pid')
532
533
534     # import ZServer stuff
535
536     # First, we need to increase the number of threads
537     if MODULE=='Zope':
538         from ZServer import setNumberOfThreads
539         setNumberOfThreads(NUMBER_OF_THREADS)
540
541     from ZServer import resolver, logger, asyncore
542
543     from ZServer import zhttp_server, zhttp_handler
544     from ZServer.WebDAVSrcHandler import WebDAVSrcHandler
545     from ZServer import PCGIServer,FTPServer,FCGIServer
546
547     from ZServer import secure_monitor_server
548
549     ## ZServer startup
550     ##
551
552     # Resolver and Logger, used by other servers
553     if DNS_IP:
554         rs = resolver.caching_resolver(DNS_IP)
555     else:
556         rs=None
557
558     if READ_ONLY:
559         lg = logger.file_logger('-') # log to stdout
560     elif os.environ.has_key('ZSYSLOG'):
561         lg = logger.syslog_logger(os.environ['ZSYSLOG'])
562         if os.environ.has_key("ZSYSLOG_FACILITY"):
563             lg = logger.syslog_logger(os.environ['ZSYSLOG'],facility=os.environ['ZSYSLOG_FACILITY'])
564         else:
565             lg = logger.syslog_logger(os.environ['ZSYSLOG'])
566     elif os.environ.has_key('ZSYSLOG_SERVER'):
567         (addr, port) = string.split(os.environ['ZSYSLOG_SERVER'], ':')
568         lg = logger.syslog_logger((addr, int(port)))
569     else:
570         lg = logger.file_logger(LOG_PATH)
571
572     # HTTP Server
573     if HTTP_PORT:
574         if type(HTTP_PORT) is type(0): HTTP_PORT=((IP_ADDRESS, HTTP_PORT),)
575         for address, port in HTTP_PORT:
576             hs = zhttp_server(
577                 ip=address,
578                 port=port,
579                 resolver=rs,
580                 logger_object=lg)
581
582             # Handler for a published module. zhttp_handler takes 3 arguments:
583             # The name of the module to publish, and optionally the URI base
584             # which is basically the SCRIPT_NAME, and optionally a dictionary
585             # with CGI environment variables which override default
586             # settings. The URI base setting is useful when you want to
587             # publish more than one module with the same HTTP server. The CGI
588             # environment setting is useful when you want to proxy requests
589             # from another web server to ZServer, and would like the CGI
590             # environment to reflect the CGI environment of the other web
591             # server.    
592             zh = zhttp_handler(MODULE, '', HTTP_ENV)
593             hs.install_handler(zh)
594
595     # HTTPS Server
596     if HTTPS_PORT:
597         if type(HTTPS_PORT) is type(0): HTTPS_PORT=((IP_ADDRESS, HTTPS_PORT),)
598         for address, port in HTTPS_PORT:
599             hs = zhttp_server(
600                 ip=address,
601                 port=port,
602                 resolver=rs,
603                 logger_object=lg)
604
605             # Handler for a published module. zhttp_handler takes 3 arguments:
606             # The name of the module to publish, and optionally the URI base
607             # which is basically the SCRIPT_NAME, and optionally a dictionary
608             # with CGI environment variables which override default
609             # settings. The URI base setting is useful when you want to
610             # publish more than one module with the same HTTP server. The CGI
611             # environment setting is useful when you want to proxy requests
612             # from another web server to ZServer, and would like the CGI
613             # environment to reflect the CGI environment of the other web
614             # server.    
615
616             try:
617                 del HTTPS_ENV['HTTP']
618             except KeyError:
619                 pass
620             HTTPS_ENV['HTTPS']='ON'
621
622             zh = zhttp_handler(MODULE, '', HTTPS_ENV)
623             hs.install_handler(zh)
624
625     # WebDAV source Server (runs HTTP, but munges request to return
626     #  'manage_FTPget').
627     if WEBDAV_SOURCE_PORT:
628         if type(WEBDAV_SOURCE_PORT) is type(0):
629             WEBDAV_SOURCE_PORT=((IP_ADDRESS, WEBDAV_SOURCE_PORT),)
630         for address, port in WEBDAV_SOURCE_PORT:
631             hs = zhttp_server(
632                 ip=address,
633                 port=port,
634                 resolver=rs,
635                 logger_object=lg)
636
637             # Handler for a published module. zhttp_handler takes 3 arguments:
638             # The name of the module to publish, and optionally the URI base
639             # which is basically the SCRIPT_NAME, and optionally a dictionary
640             # with CGI environment variables which override default
641             # settings. The URI base setting is useful when you want to
642             # publish more than one module with the same HTTP server. The CGI
643             # environment setting is useful when you want to proxy requests
644             # from another web server to ZServer, and would like the CGI
645             # environment to reflect the CGI environment of the other web
646             # server.    
647             zh = WebDAVSrcHandler(MODULE, '', HTTP_ENV)
648             hs.install_handler(zh)
649
650     # FTP Server
651     if FTP_PORT:
652         if type(FTP_PORT) is type(0): FTP_PORT=((IP_ADDRESS, FTP_PORT),)
653         for address, port in FTP_PORT:
654             FTPServer(
655                module=MODULE,
656                ip=address,
657                port=port,
658                resolver=rs,
659                logger_object=lg)
660
661     # PCGI Server
662     if PCGI_FILE and not READ_ONLY:
663         PCGI_FILE=os.path.join(here, PCGI_FILE)
664         if os.path.exists(PCGI_FILE):
665             zpcgi = PCGIServer(
666                 module=MODULE,
667                 ip=IP_ADDRESS,
668                 pcgi_file=PCGI_FILE,
669                 resolver=rs,
670                 logger_object=lg)
671
672
673     # FastCGI Server
674     if FCGI_PORT and not READ_ONLY:
675         fcgiPort = None
676         fcgiPath = None
677         try:
678             fcgiPort = string.atoi(FCGI_PORT)
679         except ValueError:
680             fcgiPath = FCGI_PORT
681         zfcgi = FCGIServer(module=MODULE,
682                            ip=IP_ADDRESS,
683                            port=fcgiPort,
684                            socket_file=fcgiPath,
685                            resolver=rs,
686                            logger_object=lg)
687
688
689     # Monitor Server
690     if MONITOR_PORT:
691         from AccessControl.User import emergency_user
692         if not hasattr(emergency_user, '__null_user__'):
693             pw = emergency_user._getPassword()
694         else:
695             pw = None
696             zLOG.LOG("z2", zLOG.WARNING, 'Monitor server not started'
697                      ' because no emergency user exists.')
698         if pw:
699             if type(MONITOR_PORT) is type(0): 
700                 MONITOR_PORT=((IP_ADDRESS, MONITOR_PORT),)
701             for address, port in MONITOR_PORT:
702                 monitor=secure_monitor_server(
703                     password=pw,
704                     hostname=address,
705                     port=port)
706
707     # Try to set uid to "-u" -provided uid.
708     # Try to set gid to  "-u" user's primary group. 
709     # This will only work if this script is run by root.
710     try:
711         import pwd
712         try:
713             try:    UID = string.atoi(UID)
714             except: pass
715             gid = None
716             if type(UID) == type(""):
717                 uid = pwd.getpwnam(UID)[2]
718                 gid = pwd.getpwnam(UID)[3]
719             elif type(UID) == type(1):
720                 uid = pwd.getpwuid(UID)[2]
721                 gid = pwd.getpwuid(UID)[3]
722             else:
723                 raise KeyError 
724             try:
725                 if gid is not None:
726                     try:
727                         os.setgid(gid)
728                     except OSError:
729                         pass
730                 os.setuid(uid)
731             except OSError:
732                 pass
733         except KeyError:
734             zLOG.LOG("z2", zLOG.ERROR, ("can't find UID %s" % UID))
735     except:
736         pass
737
738
739
740     # if it hasn't failed at this point, create a .pid file.
741     if not READ_ONLY:
742         pf = open(PID_FILE, 'w')
743         pid=str(os.getpid())
744         try: pid=str(os.getppid())+' '+pid
745         except: pass
746         pf.write(pid)
747         pf.close()
748
749 except:
750     # Log startup exception and tell zdaemon not to restart us.
751     try:
752         zLOG.LOG("z2", zLOG.PANIC, "Startup exception",
753                  error=sys.exc_info())
754     except: pass
755     sys.exit(0)
756
757 # Start Medusa, Ye Hass!
758 sys.ZServerExitCode=0
759 asyncore.loop()
760 sys.exit(sys.ZServerExitCode)