Author: johannes Date: 2007-09-27 03:57:00 -0500 (Thu, 27 Sep 2007) New Revision: 9785
Modified: trunk/gnue-common/src/apps/GBaseApp.py trunk/gnue-common/src/apps/GServerApp.py Log: Properly close the open filehandles, so we're not connected to the controlling terminal anymore. issue122 testing Modified: trunk/gnue-common/src/apps/GBaseApp.py =================================================================== --- trunk/gnue-common/src/apps/GBaseApp.py 2007-09-26 13:35:03 UTC (rev 9784) +++ trunk/gnue-common/src/apps/GBaseApp.py 2007-09-27 08:57:00 UTC (rev 9785) @@ -313,10 +313,11 @@ serr = open('nul', 'w') try: - sys.stdout.close() + os.close(sys.stdout.fileno()) sys.stdout = sout - sys.stderr.close() + os.close(sys.stderr.fileno()) sys.stderr = serr + except: pass Modified: trunk/gnue-common/src/apps/GServerApp.py =================================================================== --- trunk/gnue-common/src/apps/GServerApp.py 2007-09-26 13:35:03 UTC (rev 9784) +++ trunk/gnue-common/src/apps/GServerApp.py 2007-09-27 08:57:00 UTC (rev 9785) @@ -1,9 +1,12 @@ +# GNU Enterprise Common Library - Application Services - Server applications # -# This file is part of GNU Enterprise. +# Copyright 2001-2007 Free Software Foundation # -# GNU Enterprise is free software; you can redistribute it -# and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation; either +# This file is part of GNU Enterprise +# +# GNU Enterprise is free software; you can redistribute it +# and/or modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation; either # version 2, or (at your option) any later version. # # GNU Enterprise is distributed in the hope that it will be @@ -16,225 +19,240 @@ # write to the Free Software Foundation, Inc., 59 Temple Place # - Suite 330, Boston, MA 02111-1307, USA. # -# Copyright 2000-2007 Free Software Foundation -# -# FILE: -# GServerApp.py -# -# DESCRIPTION: -# Class that provides a basis for GNUe server applications. -# -# NOTES: -# This will eventually have features only needed by "server" -# applications, such as abstracted client RPC calls via -# CORBA, RPC-XML, SOAP, etc and daemon/forking/threading. -# +# $Id$ -from gnue.common.apps.GBaseApp import GBaseApp -from gnue.common.apps import GConfig, errors -from gnue.common.apps.GLogger import Logger import sys import os import os.path import signal +from gnue.common.apps.GBaseApp import GBaseApp +from gnue.common.apps import GConfig, errors +from gnue.common.apps.GLogger import Logger + +# ============================================================================= +# Exceptions +# ============================================================================= + class ServerRunningError (errors.UserError): - def __init__ (self, pid): - msg = u_("The server is already running on pid %s") % pid - errors.UserError.__init__ (self, msg) + """ The server is already running on a given pid """ + def __init__ (self, pid): + msg = u_("The server is already running on pid %s") % pid + errors.UserError.__init__ (self, msg) +# ============================================================================= +# Base class for server applications +# ============================================================================= + class GServerApp(GBaseApp): + """ + This is the basse class for server applications + """ - def __init__(self, connections=None, application=None, defaults=None): + # ------------------------------------------------------------------------- + # Constructor + # ------------------------------------------------------------------------- - self.COMMAND_OPTIONS.append ( - [ 'foreground','Z','no-detach',0,0, None, - u_("Do not send the server into the background. For a POSIX system, " - "this option keeps the server process from forking and detaching " - "from its controlling terminal.")], - ) + def __init__(self, connections=None, application=None, defaults=None): - self.COMMAND_OPTIONS.append ( - ['pidfile', 'P', 'pidfile', True, - '/var/run/gnue/%s.pid' % application or 'gnue', u_('pid-file'), - u_("Filename to store the server's process id.")]) + self.COMMAND_OPTIONS.append( + ['foreground','Z','no-detach',0,0, None, + u_("Do not send the server into the background. For a POSIX system, " + "this option keeps the server process from forking and detaching " + "from its controlling terminal.")], + ) - GBaseApp.__init__(self, connections, application, defaults) + self.COMMAND_OPTIONS.append( + ['pidfile', 'P', 'pidfile', True, + '/var/run/gnue/%s.pid' % application or 'gnue', u_('pid-file'), + u_("Filename to store the server's process id.")]) - if not self.OPTIONS ['foreground']: - if os.name == 'posix': - self.__removeStaleFile () - self.__createPidFile (0) - - try: - signal.signal (signal.SIGTERM, self._terminate) - except ValueError: - # signal only works in main thread, but - # in a win32 service we are not in the main thread here - pass + GBaseApp.__init__(self, connections, application, defaults) + if not self.OPTIONS['foreground']: + if os.name == 'posix': + self.__removeStaleFile() + self.__createPidFile(0) + try: + signal.signal(signal.SIGTERM, self._terminate) - # This can be overwritten by code necessary - # for startup. If overwritten, do not first - # call the original GServerApp.run(self) as - # this would send to background immediately. - # Instead, call the original GServerApp.run(self) - # after you are sure you are finished with - # startup code and are ready to go to server - # mode. - def run(self): + except ValueError: + # signal only works in main thread, but + # in a win32 service we are not in the main thread here + pass - # Fork, if applicable/possible, and send to background - if not self.OPTIONS ["foreground"]: - self.daemonize () + # ------------------------------------------------------------------------- + # Run der Server applictaion + # ------------------------------------------------------------------------- - # Called when a request to shutdown the server is received - def shutdown(self): - pass + def run(self): + """ + This can be overwritten by code necessary for startup. If overwritten, + do not first call the original GServerApp.run(self) as this would send + to background immediately. Instead, call the original + GServerApp.run(self) after you are sure you are finished with startup + code and are ready to go to server mode. + """ + # Fork, if applicable/possible, and send to background + if not self.OPTIONS["foreground"]: + self.daemonize() - # Turn ourselves into a daemon/service/etc. - # Returns 1 if program successfully converted, - # 0 otherwise. - # - def daemonize (self): - # For an overview of what we're doing here, - # check out the Unix Programmer's FAQ at: - # http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + # ------------------------------------------------------------------------- + # Shutdown the server application + # ------------------------------------------------------------------------- - # We enclose these actions in try: blocks so that - # this doesn't fail on non-Unix environments. + def shutdown(self): + """ + Called when a request to shutdown the server is received + """ + pass - self.__removeStaleFile () - try: - # Fork #1 - pid = os.fork() - if pid != 0: - # Close main process - sys.exit(0) + # ------------------------------------------------------------------------- + # Daemonize the server application + # ------------------------------------------------------------------------- - # Open new filehandles for stdin, stdout, stderr - # TODO: This may eventually be log files. - sin = open('/dev/null','r') - sout = open('/dev/null','w') - serr = open('/dev/null','w') + def daemonize(self): + """ + Turn ourselves into a daemon/service/etc. - except AttributeError: - return 0 - except IOError: - return 0 - except OSError: - return 0 + @returns: 1 if the program successfully converted, 0 otherwise + """ + # For an overview of what we're doing here, check out the Unix + # Programmer's FAQ at: + # http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 - # Disassociate ourselves - try: - os.chdir('/') - os.setsid() - os.umask(0) - except AttributeError: - pass - except OSError: - pass + # We enclose these actions in try: blocks so that this doesn't fail on + # non-Unix environments. + self.__removeStaleFile() - try: - # Fork #2 - pid = os.fork() - if pid != 0: - self.__createPidFile (pid) + try: + # Fork #1 + pid = os.fork() + if pid != 0: + # Close main process + sys.exit(0) - sys.exit(0) - except OSError: - pass + except AttributeError: + return 0 + except IOError: + return 0 + except OSError: + return 0 - # Redirect all the stdio channels. - # (after all, we have no terminal :) - try: - sys.stdin.close() - sys.stdin = sin + # Disassociate ourselves + try: + os.chdir('/') + os.setsid() + os.umask(0) + except AttributeError: + pass + except OSError: + pass - sys.stdout.close() - sys.stdout = sout - sys.stderr.close() - sys.stderr = serr - except AttributeError: - pass + try: + # Fork #2 + pid = os.fork() + if pid != 0: + self.__createPidFile(pid) - return 1 + sys.exit(0) + except OSError: + pass - # --------------------------------------------------------------------------- - # Create a new pid file - # --------------------------------------------------------------------------- + # Redirect all the stdio channels. + # (after all, we have no terminal :) + try: + os.close(sys.stdin.fileno()) + sys.stdin = open('/dev/null','r') - def __createPidFile (self, pid): - """ - This function creates a new pid file for the current process. + os.close(sys.stdout.fileno()) + sys.stdout = open('/dev/null','w') - @param pid: Process id to store in the pid file - """ + os.close(sys.stderr.fileno()) + sys.stderr = serr = open('/dev/null','w') - piddir = os.path.dirname (self.OPTIONS ['pidfile']) - if not os.path.exists (piddir): - os.makedirs (piddir) + except AttributeError: + pass - pidfile = open (self.OPTIONS ['pidfile'], 'w') - pidfile.write ("%s%s" % (pid, os.linesep)) - pidfile.close () + return 1 - # --------------------------------------------------------------------------- - # Remove a stale pid file - # --------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + # Create a new pid file + # ------------------------------------------------------------------------- - def __removeStaleFile (self): - """ - This function checks for a stale pid file. If a file exists, this function - raises a ServerRunningError exception if the process is till alive. - """ + def __createPidFile(self, pid): + """ + This function creates a new pid file for the current process. - if os.path.exists (self.OPTIONS ['pidfile']): - pidfile = open (self.OPTIONS ['pidfile'], 'r') + @param pid: Process id to store in the pid file + """ - try: - oldPid = int (pidfile.readline ().strip ()) + piddir = os.path.dirname(self.OPTIONS['pidfile']) + if not os.path.exists(piddir): + os.makedirs(piddir) - if oldPid: - try: - os.kill (oldPid, 0) + pidfile = open(self.OPTIONS['pidfile'], 'w') + pidfile.write("%s%s" % (pid, os.linesep)) + pidfile.close() - except OSError: - # remove the stale pid-file - os.unlink (self.OPTIONS ['pidfile']) - else: - raise ServerRunningError, oldPid + # ------------------------------------------------------------------------- + # Remove a stale pid file + # ------------------------------------------------------------------------- - finally: - pidfile.close () + def __removeStaleFile(self): + """ + This function checks for a stale pid file. If a file exists, this + function raises a ServerRunningError exception if the process is till + alive. + """ + if os.path.exists(self.OPTIONS['pidfile']): + pidfile = open(self.OPTIONS['pidfile'], 'r') - # --------------------------------------------------------------------------- - # Handle a SIGTERM signal - # --------------------------------------------------------------------------- + try: + old_pid = int(pidfile.readline().strip()) - def _terminate (self, signal, frame): - """ - This function handles a SIGTERM signal and removes the pid-file if the - server is running in the background. - """ + if old_pid: + try: + os.kill(old_pid, 0) - if not self.OPTIONS ["foreground"] and \ - os.path.exists (self.OPTIONS ['pidfile']): - os.unlink (self.OPTIONS ['pidfile']) + except OSError: + # remove the stale pid-file + os.unlink(self.OPTIONS['pidfile']) - sys.exit () + else: + raise ServerRunningError, old_pid + + finally: + pidfile.close() + + + # ------------------------------------------------------------------------- + # Handle a SIGTERM signal + # ------------------------------------------------------------------------- + + def _terminate(self, signal, frame): + """ + This function handles a SIGTERM signal and removes the pid-file if the + server is running in the background. + """ + + if not self.OPTIONS["foreground"] and \ + os.path.exists(self.OPTIONS['pidfile']): + os.unlink(self.OPTIONS['pidfile']) + + sys.exit() _______________________________________________ commit-gnue mailing list commit-gnue@gnu.org http://lists.gnu.org/mailman/listinfo/commit-gnue