SF.net SVN: tmda: [2178] trunk/tmda/bin/tmda-ofmipd

[email protected] Thu, 15 Mar 2007 22:13:21 -0700
Newsgroups gmane.mail.spam.tmda.cvs
Message-ID <[email protected]>
Revision: 2178
          http://svn.sourceforge.net/tmda/?rev=2178&view=rev
Author:   srwarren
Date:     2007-03-15 22:13:20 -0700 (Thu, 15 Mar 2007)

Log Message:
-----------
tmda-ofmipd: When run in the background, daemonize properly, per the instructions on how to do this from:

http://www.enderunix.org/docs/eng/daemon.php

This appears to work under Python 2.3, 2,4, 2.5 on both Linux and NetBSD.

The "if True:" wrapper around the added code will allow it to be easily reverted for testing any OS/whatever-specific issues. This will be removed after a release or two without any reported problems.

Modified Paths:
--------------
    trunk/tmda/bin/tmda-ofmipd

Modified: trunk/tmda/bin/tmda-ofmipd
===================================================================
--- trunk/tmda/bin/tmda-ofmipd	2007-03-15 03:09:24 UTC (rev 2177)
+++ trunk/tmda/bin/tmda-ofmipd	2007-03-16 05:13:20 UTC (rev 2178)
@@ -885,6 +885,10 @@
     SMTPSession(conn, process_msg_func)
 
 
+def sig_handler(sig_num, frame):
+    sys.exit()
+
+
 # Main code begins
 
 
@@ -1363,6 +1367,7 @@
         host, port = opts.proxyport.split(':', 1)
         server = SMTPServer((host, int(port)), process_msg_func)
 
+    # Switch user/group ID, etc.
     if running_as_root:
         pw_uid = Util.getuid(opts.username)
         # check ownership of authfile if using only remote
@@ -1371,18 +1376,45 @@
             if Util.getfileuid(opts.authfile) <> pw_uid:
                 raise IOError, \
                     opts.authfile + ' must be owned by UID ' + str(pw_uid)
-        # try setegid()
+        # Set group ID
         os.setegid(Util.getgid(opts.username))
-        # try setting the supplemental group ids
+        # Set supplemental group ids
         os.setgroups(Util.getgrouplist(opts.username))
-        # try seteuid()
+        # Set user ID
         os.seteuid(pw_uid)
 
+    # Daemonize the process if required
     if not (opts.foreground or opts.one_session):
-        signal.signal(signal.SIGHUP, signal.SIG_IGN) # ignore SIGHUP
         if os.fork() <> 0:
             sys.exit()
 
+        if True:
+            os.setsid()
+
+            if os.fork() <> 0:
+                sys.exit()
+
+            os.setpgrp()
+
+            # Theoretically we should close all FDs in
+            # range(os.getdtablesize()), but the API doesn't exist!
+            os.close(0)
+            os.close(1)
+            os.close(2)
+            os.open('/dev/null', os.O_RDWR | os.O_NOCTTY)
+            os.dup(0)
+            os.dup(0)
+            sys.stdin = os.fdopen(0, 'r')
+            sys.stdout = os.fdopen(1, 'w')
+            sys.stderr = os.fdopen(2, 'w')
+
+            signal.signal(signal.SIGTSTP, signal.SIG_IGN);
+            signal.signal(signal.SIGTTOU, signal.SIG_IGN);
+            signal.signal(signal.SIGTTIN, signal.SIG_IGN);
+
+            signal.signal(signal.SIGHUP, sig_handler);
+            signal.signal(signal.SIGTERM, sig_handler);
+
     # Start the event loop
     try:
         asyncore.loop()


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.