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(). */
/* 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)
}
}
-/* 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)
{
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 {
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;
} 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);
}
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
{
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;