/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <config.h>
#include "daemon.h"
-#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include "fatal-signal.h"
#include "dirs.h"
#include "lockfile.h"
+#include "ovs-thread.h"
#include "process.h"
#include "socket-util.h"
#include "timeval.h"
static void check_already_running(void);
static int lock_pidfile(FILE *, int command);
+static char *make_pidfile_name(const char *name);
+static pid_t fork_and_clean_up(void);
+static void daemonize_post_detach(void);
/* 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 *
+static char *
make_pidfile_name(const char *name)
{
return (!name
void
set_pidfile(const char *name)
{
+ assert_single_threaded();
free(pidfile);
pidfile = make_pidfile_name(name);
}
-/* Returns an absolute path to the configured pidfile, or a null pointer if no
- * pidfile is configured. The caller must not modify or free the returned
- * string. */
-const char *
-get_pidfile(void)
-{
- return pidfile;
-}
-
/* Sets that we do not chdir to "/". */
void
set_no_chdir(void)
chdir_ = false;
}
-/* Will we chdir to "/" as part of daemonizing? */
-bool
-is_chdir_enabled(void)
-{
- return chdir_;
-}
-
/* Normally, daemonize() or damonize_start() will terminate the program with a
* message if a locked pidfile already exists. If this function is called, an
* existing pidfile will be replaced, with a warning. */
void
daemon_save_fd(int fd)
{
- assert(fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO);
+ ovs_assert(fd == STDIN_FILENO ||
+ fd == STDOUT_FILENO ||
+ fd == STDERR_FILENO);
save_fds[fd] = true;
}
file = fopen(tmpfile, "a+");
if (!file) {
- VLOG_FATAL("%s: create failed (%s)", tmpfile, strerror(errno));
+ VLOG_FATAL("%s: create failed (%s)", tmpfile, ovs_strerror(errno));
}
error = lock_pidfile(file, F_SETLK);
/* Looks like we failed to acquire the lock. Note that, if we failed
* for some other reason (and '!overwrite_pidfile'), we will have
* left 'tmpfile' as garbage in the file system. */
- VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile, strerror(error));
+ VLOG_FATAL("%s: fcntl(F_SETLK) failed (%s)", tmpfile,
+ ovs_strerror(error));
}
if (!overwrite_pidfile) {
}
if (fstat(fileno(file), &s) == -1) {
- VLOG_FATAL("%s: fstat failed (%s)", tmpfile, strerror(errno));
+ VLOG_FATAL("%s: fstat failed (%s)", tmpfile, ovs_strerror(errno));
}
if (ftruncate(fileno(file), 0) == -1) {
- VLOG_FATAL("%s: truncate failed (%s)", tmpfile, strerror(errno));
+ VLOG_FATAL("%s: truncate failed (%s)", tmpfile, ovs_strerror(errno));
}
fprintf(file, "%ld\n", pid);
if (fflush(file) == EOF) {
- VLOG_FATAL("%s: write failed (%s)", tmpfile, strerror(errno));
+ VLOG_FATAL("%s: write failed (%s)", tmpfile, ovs_strerror(errno));
}
error = rename(tmpfile, pidfile);
if (error < 0) {
VLOG_FATAL("failed to rename \"%s\" to \"%s\" (%s)",
- tmpfile, pidfile, strerror(errno));
+ tmpfile, pidfile, ovs_strerror(errno));
}
/* Ensure that the pidfile will get deleted on exit. */
pidfile_dev = s.st_dev;
pidfile_ino = s.st_ino;
free(tmpfile);
- free(pidfile);
- pidfile = NULL;
}
/* If configured with set_pidfile() or set_detach(), creates the pid file and
* Post-fork, but before returning, this function calls a few other functions
* that are generally useful if the child isn't planning to exec a new
* process. */
-pid_t
+static pid_t
fork_and_clean_up(void)
{
- pid_t pid;
-
- pid = fork();
+ pid_t pid = xfork();
if (pid > 0) {
/* Running in parent process. */
fatal_signal_fork();
} else if (!pid) {
/* Running in child process. */
- time_postfork();
lockfile_postfork();
- } else {
- VLOG_FATAL("fork failed (%s)", strerror(errno));
}
-
return pid;
}
status_msg);
}
} else if (retval < 0) {
- VLOG_FATAL("waitpid failed (%s)", strerror(errno));
+ VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno));
} else {
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
}
close(fds[0]);
error = write_fully(fd, "", 1, &bytes_written);
if (error) {
- VLOG_FATAL("pipe write failed (%s)", strerror(error));
+ VLOG_FATAL("pipe write failed (%s)", ovs_strerror(error));
}
close(fd);
{
if (WIFSIGNALED(status)) {
static const int error_signals[] = {
+ /* This list of signals is documented in daemon.man. If you
+ * change the list, update the documentation too. */
SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGILL, SIGPIPE, SIGSEGV,
SIGXCPU, SIGXFSZ
};
char *status_msg;
int crashes;
- subprogram_name = "monitor";
+ set_subprogram_name("monitor");
status_msg = xstrdup("healthy");
last_restart = TIME_MIN;
crashes = 0;
} while (retval == -1 && errno == EINTR);
if (retval == -1) {
- VLOG_FATAL("waitpid failed (%s)", strerror(errno));
+ VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno));
} else if (retval == daemon_pid) {
char *s = process_status_msg(status);
if (should_restart(status)) {
r.rlim_max = 0;
if (setrlimit(RLIMIT_CORE, &r) == -1) {
VLOG_WARN("failed to disable core dumps: %s",
- strerror(errno));
+ ovs_strerror(errno));
}
}
/* Running in new daemon process. */
proctitle_restore();
- subprogram_name = "";
+ set_subprogram_name("");
}
/* Close standard file descriptors (except any that the client has requested we
void
daemonize_start(void)
{
+ assert_single_threaded();
daemonize_fd = -1;
if (detach) {
/* Running in daemon process. */
}
+ forbid_forking("running in daemon process");
+
if (pidfile) {
make_pidfile();
}
void
daemonize_complete(void)
{
+ if (pidfile) {
+ free(pidfile);
+ pidfile = NULL;
+ }
+
if (!detached) {
detached = true;
* It only makes sense to call this function as part of an implementation of a
* special daemon subprocess. A normal daemon should just call
* daemonize_complete(). */
-void
+static void
daemonize_post_detach(void)
{
if (detach) {
return 0;
}
error = errno;
- VLOG_WARN("%s: open: %s", pidfile, strerror(error));
+ VLOG_WARN("%s: open: %s", pidfile, ovs_strerror(error));
goto error;
}
error = lock_pidfile__(file, F_GETLK, &lck);
if (error) {
- VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error));
+ VLOG_WARN("%s: fcntl: %s", pidfile, ovs_strerror(error));
goto error;
}
if (lck.l_type == F_UNLCK) {
if (unlink(pidfile)) {
error = errno;
VLOG_WARN("%s: failed to delete stale pidfile (%s)",
- pidfile, strerror(error));
+ pidfile, ovs_strerror(error));
goto error;
}
VLOG_DBG("%s: deleted stale pidfile", pidfile);
if (!fgets(line, sizeof line, file)) {
if (ferror(file)) {
error = errno;
- VLOG_WARN("%s: read: %s", pidfile, strerror(error));
+ VLOG_WARN("%s: read: %s", pidfile, ovs_strerror(error));
} else {
error = ESRCH;
VLOG_WARN("%s: read: unexpected end of file", pidfile);
VLOG_FATAL("%s: already running as pid %ld, aborting", pidfile, pid);
} else if (pid < 0) {
VLOG_FATAL("%s: pidfile check failed (%s), aborting",
- pidfile, strerror(-pid));
+ pidfile, ovs_strerror(-pid));
}
}
+
+\f
+/* stub functions for non-windows platform. */
+
+void
+service_start(int *argc OVS_UNUSED, char **argv[] OVS_UNUSED)
+{
+}
+
+void
+service_stop(void)
+{
+}
+
+bool
+should_service_stop(void)
+{
+ return false;
+}