ofp-print: Make output easier to read.
[cascardo/ovs.git] / lib / daemon.c
index 6cb553a..bbcfe6a 100644 (file)
 
 VLOG_DEFINE_THIS_MODULE(daemon)
 
-/* Should we run in the background? */
+/* --detach: Should we run in the background? */
 static bool detach;
 
-/* Name of pidfile (null if none). */
+/* --pidfile: Name of pidfile (null if none). */
 static char *pidfile;
 
-/* Create pidfile even if one already exists and is locked? */
+/* Device and inode of pidfile, so we can avoid reopening it. */
+static dev_t pidfile_dev;
+static ino_t pidfile_ino;
+
+/* --overwrite-pidfile: Create pidfile even if one already exists and is
+   locked? */
 static bool overwrite_pidfile;
 
-/* Should we chdir to "/"? */
+/* --no-chdir: Should we chdir to "/"? */
 static bool chdir_ = true;
 
 /* File descriptor used by daemonize_start() and daemonize_complete(). */
@@ -58,7 +63,7 @@ static bool monitor;
 /* Returns the file name that would be used for a pidfile if 'name' were
  * provided to set_pidfile().  The caller must free the returned string. */
 char *
-make_pidfile_name(const char *name) 
+make_pidfile_name(const char *name)
 {
     return (!name
             ? xasprintf("%s/%s.pid", ovs_rundir, program_name)
@@ -174,9 +179,9 @@ die_if_already_running(void)
     }
 }
 
-/* If a pidfile has been configured, creates it and stores the running process'
- * pid init.  Ensures that the pidfile will be deleted when the process
- * exits. */
+/* If a pidfile has been configured, creates it and stores the running
+ * process's pid in it.  Ensures that the pidfile will be deleted when the
+ * process exits. */
 static void
 make_pidfile(void)
 {
@@ -207,6 +212,15 @@ make_pidfile(void)
                         close(fd);
                     } else {
                         /* Keep 'fd' open to retain the lock. */
+                        struct stat s;
+
+                        if (!fstat(fd, &s)) {
+                            pidfile_dev = s.st_dev;
+                            pidfile_ino = s.st_ino;
+                        } else {
+                            VLOG_ERR("%s: fstat failed: %s",
+                                     pidfile, strerror(errno));
+                        }
                     }
                     free(text);
                 } else {
@@ -329,11 +343,13 @@ monitor_daemon(pid_t daemon_pid)
     const char *saved_program_name;
     time_t last_restart;
     char *status_msg;
+    int crashes;
 
     saved_program_name = program_name;
     program_name = xasprintf("monitor(%s)", program_name);
     status_msg = xstrdup("healthy");
     last_restart = TIME_MIN;
+    crashes = 0;
     for (;;) {
         int retval;
         int status;
@@ -351,7 +367,8 @@ monitor_daemon(pid_t daemon_pid)
         } else if (retval == daemon_pid) {
             char *s = process_status_msg(status);
             free(status_msg);
-            status_msg = xasprintf("pid %lu died, %s",
+            status_msg = xasprintf("%d crashes: pid %lu died, %s",
+                                   ++crashes,
                                    (unsigned long int) daemon_pid, s);
             free(s);
 
@@ -448,6 +465,10 @@ daemonize_start(void)
     }
 
     make_pidfile();
+
+    /* Make sure that the unixctl commands for vlog get registered in a
+     * daemon, even before the first log message. */
+    vlog_init();
 }
 
 /* If daemonization is configured, then this function notifies the parent
@@ -486,9 +507,21 @@ read_pidfile(const char *pidfile)
 {
     char line[128];
     struct flock lck;
+    struct stat s;
     FILE *file;
     int error;
 
+    if ((pidfile_ino || pidfile_dev)
+        && !stat(pidfile, &s)
+        && s.st_ino == pidfile_ino && s.st_dev == pidfile_dev) {
+        /* It's our own pidfile.  We can't afford to open it, because closing
+         * *any* fd for a file that a process has locked also releases all the
+         * locks on that file.
+         *
+         * Fortunately, we know the associated pid anyhow: */
+        return getpid();
+    }
+
     file = fopen(pidfile, "r");
     if (!file) {
         error = errno;