ofp-util: Fix use-after-free in group append.
[cascardo/ovs.git] / python / ovs / daemon.py
index 864a163..bd06195 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010, 2011 Nicira Networks
+# Copyright (c) 2010, 2011, 2012 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
 
 import errno
 import fcntl
-import logging
 import os
 import resource
 import signal
@@ -23,11 +22,13 @@ import time
 
 import ovs.dirs
 import ovs.fatal_signal
-#import ovs.lockfile
 import ovs.process
 import ovs.socket_util
 import ovs.timeval
 import ovs.util
+import ovs.vlog
+
+vlog = ovs.vlog.Vlog("daemon")
 
 # --detach: Should we run in the background?
 _detach = False
@@ -76,23 +77,12 @@ def set_pidfile(name):
     _pidfile = make_pidfile_name(name)
 
 
-def get_pidfile():
-    """Returns an absolute path to the configured pidfile, or None if no
-    pidfile is configured."""
-    return _pidfile
-
-
 def set_no_chdir():
     """Sets that we do not chdir to "/"."""
     global _chdir
     _chdir = False
 
 
-def is_chdir_enabled():
-    """Will we chdir to "/" as part of daemonizing?"""
-    return _chdir
-
-
 def ignore_existing_pidfile():
     """Normally, daemonize() or daemonize_start() will terminate the program
     with a message if a locked pidfile already exists.  If this function is
@@ -121,7 +111,7 @@ def set_monitor():
 
 
 def _fatal(msg):
-    logging.error(msg)
+    vlog.err(msg)
     sys.stderr.write("%s\n" % msg)
     sys.exit(1)
 
@@ -139,33 +129,33 @@ def _make_pidfile():
         # This is global to keep Python from garbage-collecting and
         # therefore closing our file after this function exits.  That would
         # unlock the lock for us, and we don't want that.
-        global file
+        global file_handle
 
         file_handle = open(tmpfile, "w")
-    except IOError, e:
+    except IOError as e:
         _fatal("%s: create failed (%s)" % (tmpfile, e.strerror))
 
     try:
         s = os.fstat(file_handle.fileno())
-    except IOError, e:
+    except IOError as e:
         _fatal("%s: fstat failed (%s)" % (tmpfile, e.strerror))
 
     try:
         file_handle.write("%s\n" % pid)
         file_handle.flush()
-    except OSError, e:
+    except OSError as e:
         _fatal("%s: write failed: %s" % (tmpfile, e.strerror))
 
     try:
         fcntl.lockf(file_handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
-    except IOError, e:
+    except IOError as e:
         _fatal("%s: fcntl failed: %s" % (tmpfile, e.strerror))
 
     # Rename or link it to the correct name.
     if _overwrite_pidfile:
         try:
             os.rename(tmpfile, _pidfile)
-        except OSError, e:
+        except OSError as e:
             _fatal("failed to rename \"%s\" to \"%s\" (%s)"
                    % (tmpfile, _pidfile, e.strerror))
     else:
@@ -173,7 +163,7 @@ def _make_pidfile():
             try:
                 os.link(tmpfile, _pidfile)
                 error = 0
-            except OSError, e:
+            except OSError as e:
                 error = e.errno
             if error == errno.EEXIST:
                 _check_already_running()
@@ -209,7 +199,7 @@ def _waitpid(pid, options):
     while True:
         try:
             return os.waitpid(pid, options)
-        except OSError, e:
+        except OSError as e:
             if e.errno == errno.EINTR:
                 pass
             return -e.errno, 0
@@ -218,13 +208,13 @@ def _waitpid(pid, options):
 def _fork_and_wait_for_startup():
     try:
         rfd, wfd = os.pipe()
-    except OSError, e:
+    except OSError as e:
         sys.stderr.write("pipe failed: %s\n" % os.strerror(e.errno))
         sys.exit(1)
 
     try:
         pid = os.fork()
-    except OSError, e:
+    except OSError as e:
         sys.stderr.write("could not fork: %s\n" % os.strerror(e.errno))
         sys.exit(1)
 
@@ -236,20 +226,26 @@ def _fork_and_wait_for_startup():
             try:
                 s = os.read(rfd, 1)
                 error = 0
-            except OSError, e:
+            except OSError as e:
                 s = ""
                 error = e.errno
             if error != errno.EINTR:
                 break
         if len(s) != 1:
             retval, status = _waitpid(pid, 0)
-            if (retval == pid and
-                os.WIFEXITED(status) and os.WEXITSTATUS(status)):
-                # Child exited with an error.  Convey the same error to
-                # our parent process as a courtesy.
-                sys.exit(os.WEXITSTATUS(status))
+            if retval == pid:
+                if os.WIFEXITED(status) and os.WEXITSTATUS(status):
+                    # Child exited with an error.  Convey the same error to
+                    # our parent process as a courtesy.
+                    sys.exit(os.WEXITSTATUS(status))
+                else:
+                    sys.stderr.write("fork child failed to signal "
+                                     "startup (%s)\n"
+                                     % ovs.process.status_msg(status))
             else:
-                sys.stderr.write("fork child failed to signal startup\n")
+                assert retval < 0
+                sys.stderr.write("waitpid failed (%s)\n"
+                                 % os.strerror(-retval))
                 sys.exit(1)
 
         os.close(rfd)
@@ -257,7 +253,6 @@ def _fork_and_wait_for_startup():
         # Running in parent process.
         os.close(rfd)
         ovs.timeval.postfork()
-        #ovs.lockfile.postfork()
 
         global _daemonize_fd
         _daemonize_fd = wfd
@@ -306,31 +301,32 @@ def _monitor_daemon(daemon_pid):
                     try:
                         resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
                     except resource.error:
-                        logging.warning("failed to disable core dumps")
+                        vlog.warn("failed to disable core dumps")
 
                 # Throttle restarts to no more than once every 10 seconds.
                 if (last_restart is not None and
                     ovs.timeval.msec() < last_restart + 10000):
-                    logging.warning("%s, waiting until 10 seconds since last "
-                                    "restart" % status_msg)
+                    vlog.warn("%s, waiting until 10 seconds since last "
+                              "restart" % status_msg)
                     while True:
                         now = ovs.timeval.msec()
                         wakeup = last_restart + 10000
                         if now > wakeup:
                             break
-                        print "sleep %f" % ((wakeup - now) / 1000.0)
+                        sys.stdout.write("sleep %f\n" % (
+                            (wakeup - now) / 1000.0))
                         time.sleep((wakeup - now) / 1000.0)
                 last_restart = ovs.timeval.msec()
 
-                logging.error("%s, restarting" % status_msg)
+                vlog.err("%s, restarting" % status_msg)
                 daemon_pid = _fork_and_wait_for_startup()
                 if not daemon_pid:
                     break
             else:
-                logging.info("%s, exiting" % status_msg)
+                vlog.info("%s, exiting" % status_msg)
                 sys.exit(0)
 
-   # Running in new daemon process.
+    # Running in new daemon process.
 
 
 def _close_standard_fds():
@@ -354,7 +350,9 @@ def daemonize_start():
         if _fork_and_wait_for_startup() > 0:
             # Running in parent process.
             sys.exit(0)
+
         # Running in daemon or monitor process.
+        os.setsid()
 
     if _monitor:
         saved_daemonize_fd = _daemonize_fd
@@ -376,7 +374,6 @@ def daemonize_complete():
     _fork_notify_startup(_daemonize_fd)
 
     if _detach:
-        os.setsid()
         if _chdir:
             os.chdir("/")
         _close_standard_fds()
@@ -408,10 +405,10 @@ def __read_pidfile(pidfile, delete_if_stale):
 
     try:
         file_handle = open(pidfile, "r+")
-    except IOError, e:
+    except IOError as e:
         if e.errno == errno.ENOENT and delete_if_stale:
             return 0
-        logging.warning("%s: open: %s" % (pidfile, e.strerror))
+        vlog.warn("%s: open: %s" % (pidfile, e.strerror))
         return -e.errno
 
     # Python fcntl doesn't directly support F_GETLK so we have to just try
@@ -422,7 +419,7 @@ def __read_pidfile(pidfile, delete_if_stale):
         # pidfile exists but wasn't locked by anyone.  Now we have the lock.
         if not delete_if_stale:
             file_handle.close()
-            logging.warning("%s: pid file is stale" % pidfile)
+            vlog.warn("%s: pid file is stale" % pidfile)
             return -errno.ESRCH
 
         # Is the file we have locked still named 'pidfile'?
@@ -435,34 +432,34 @@ def __read_pidfile(pidfile, delete_if_stale):
         except IOError:
             raced = True
         if raced:
-            logging.warning("%s: lost race to delete pidfile" % pidfile)
+            vlog.warn("%s: lost race to delete pidfile" % pidfile)
             return -errno.EALREADY
 
         # We won the right to delete the stale pidfile.
         try:
             os.unlink(pidfile)
-        except IOError, e:
-            logging.warning("%s: failed to delete stale pidfile (%s)"
+        except IOError as e:
+            vlog.warn("%s: failed to delete stale pidfile (%s)"
                             % (pidfile, e.strerror))
             return -e.errno
         else:
-            logging.debug("%s: deleted stale pidfile" % pidfile)
+            vlog.dbg("%s: deleted stale pidfile" % pidfile)
             file_handle.close()
             return 0
-    except IOError, e:
+    except IOError as e:
         if e.errno not in [errno.EACCES, errno.EAGAIN]:
-            logging.warn("%s: fcntl: %s" % (pidfile, e.strerror))
+            vlog.warn("%s: fcntl: %s" % (pidfile, e.strerror))
             return -e.errno
 
     # Someone else has the pidfile locked.
     try:
         try:
             error = int(file_handle.readline())
-        except IOError, e:
-            logging.warning("%s: read: %s" % (pidfile, e.strerror))
+        except IOError as e:
+            vlog.warn("%s: read: %s" % (pidfile, e.strerror))
             error = -e.errno
         except ValueError:
-            logging.warning("%s does not contain a pid" % pidfile)
+            vlog.warn("%s does not contain a pid" % pidfile)
             error = -errno.EINVAL
 
         return error
@@ -501,7 +498,7 @@ def add_args(parser):
             help="Do not chdir to '/'.")
     group.add_argument("--monitor", action="store_true",
             help="Monitor %s process." % ovs.util.PROGRAM_NAME)
-    group.add_argument("--pidfile", nargs="?", default=pidfile,
+    group.add_argument("--pidfile", nargs="?", const=pidfile,
             help="Create pidfile (default %s)." % pidfile)
     group.add_argument("--overwrite-pidfile", action="store_true",
             help="With --pidfile, start even if already running.")