-/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 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 <getopt.h>
#include <inttypes.h>
#include <signal.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "column.h"
#include "command-line.h"
#include "daemon.h"
#include "dirs.h"
-#include "dummy.h"
#include "dynamic-string.h"
+#include "fatal-signal.h"
#include "file.h"
#include "hash.h"
#include "json.h"
#include "trigger.h"
#include "util.h"
#include "unixctl.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(ovsdb_server);
static unixctl_cb_func ovsdb_server_list_databases;
static char *open_db(struct server_config *config, const char *filename);
+static void close_db(struct db *db);
static void parse_options(int *argc, char **argvp[],
struct sset *remotes, char **unixctl_pathp,
char **run_command);
-static void usage(void) NO_RETURN;
+OVS_NO_RETURN static void usage(void);
static char *reconfigure_remotes(struct ovsdb_jsonrpc_server *,
const struct shash *all_dbs,
static void load_config(FILE *config_file, struct sset *remotes,
struct sset *db_filenames);
+static void
+main_loop(struct ovsdb_jsonrpc_server *jsonrpc, struct shash *all_dbs,
+ struct unixctl_server *unixctl, struct sset *remotes,
+ struct process *run_process, bool *exiting)
+{
+ char *remotes_error, *ssl_error;
+ struct shash_node *node;
+ long long int status_timer = LLONG_MIN;
+
+ *exiting = false;
+ ssl_error = NULL;
+ remotes_error = NULL;
+ while (!*exiting) {
+ memory_run();
+ if (memory_should_report()) {
+ struct simap usage;
+
+ simap_init(&usage);
+ ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
+ SHASH_FOR_EACH(node, all_dbs) {
+ struct db *db = node->data;
+ ovsdb_get_memory_usage(db->db, &usage);
+ }
+ memory_report(&usage);
+ simap_destroy(&usage);
+ }
+
+ /* Run unixctl_server_run() before reconfigure_remotes() because
+ * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
+ * the set of remotes that reconfigure_remotes() uses. */
+ unixctl_server_run(unixctl);
+
+ report_error_if_changed(
+ reconfigure_remotes(jsonrpc, all_dbs, remotes),
+ &remotes_error);
+ report_error_if_changed(reconfigure_ssl(all_dbs), &ssl_error);
+ ovsdb_jsonrpc_server_run(jsonrpc);
+
+ SHASH_FOR_EACH(node, all_dbs) {
+ struct db *db = node->data;
+ ovsdb_trigger_run(db->db, time_msec());
+ }
+ if (run_process) {
+ process_run();
+ if (process_exited(run_process)) {
+ *exiting = true;
+ }
+ }
+
+ /* update Manager status(es) every 5 seconds */
+ if (time_msec() >= status_timer) {
+ status_timer = time_msec() + 5000;
+ update_remote_status(jsonrpc, remotes, all_dbs);
+ }
+
+ memory_wait();
+ ovsdb_jsonrpc_server_wait(jsonrpc);
+ unixctl_server_wait(unixctl);
+ SHASH_FOR_EACH(node, all_dbs) {
+ struct db *db = node->data;
+ ovsdb_trigger_wait(db->db, time_msec());
+ }
+ if (run_process) {
+ process_wait(run_process);
+ }
+ if (*exiting) {
+ poll_immediate_wake();
+ }
+ poll_timer_wait_until(status_timer);
+ poll_block();
+ if (should_service_stop()) {
+ *exiting = true;
+ }
+ }
+
+}
+
int
main(int argc, char *argv[])
{
struct process *run_process;
bool exiting;
int retval;
- long long int status_timer = LLONG_MIN;
FILE *config_tmpfile;
struct server_config server_config;
struct shash all_dbs;
- struct shash_node *node;
- char *remotes_error, *ssl_error;
+ struct shash_node *node, *next;
char *error;
int i;
- proctitle_init(argc, argv);
+ ovs_cmdl_proctitle_init(argc, argv);
set_program_name(argv[0]);
- signal(SIGPIPE, SIG_IGN);
+ service_start(&argc, &argv);
+ fatal_ignore_sigpipe();
process_init();
parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
unixctl_command_register("ovsdb-server/list-dbs", "", 0, 0,
ovsdb_server_list_databases, &all_dbs);
- exiting = false;
- ssl_error = NULL;
- remotes_error = NULL;
- while (!exiting) {
- memory_run();
- if (memory_should_report()) {
- struct simap usage;
+ main_loop(jsonrpc, &all_dbs, unixctl, &remotes, run_process, &exiting);
- simap_init(&usage);
- ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
- SHASH_FOR_EACH(node, &all_dbs) {
- struct db *db = node->data;
- ovsdb_get_memory_usage(db->db, &usage);
- }
- memory_report(&usage);
- simap_destroy(&usage);
- }
-
- /* Run unixctl_server_run() before reconfigure_remotes() because
- * ovsdb-server/add-remote and ovsdb-server/remove-remote can change
- * the set of remotes that reconfigure_remotes() uses. */
- unixctl_server_run(unixctl);
-
- report_error_if_changed(
- reconfigure_remotes(jsonrpc, &all_dbs, &remotes),
- &remotes_error);
- report_error_if_changed(reconfigure_ssl(&all_dbs), &ssl_error);
- ovsdb_jsonrpc_server_run(jsonrpc);
-
- SHASH_FOR_EACH(node, &all_dbs) {
- struct db *db = node->data;
- ovsdb_trigger_run(db->db, time_msec());
- }
- if (run_process) {
- process_run();
- if (process_exited(run_process)) {
- exiting = true;
- }
- }
-
- /* update Manager status(es) every 5 seconds */
- if (time_msec() >= status_timer) {
- status_timer = time_msec() + 5000;
- update_remote_status(jsonrpc, &remotes, &all_dbs);
- }
-
- memory_wait();
- ovsdb_jsonrpc_server_wait(jsonrpc);
- unixctl_server_wait(unixctl);
- SHASH_FOR_EACH(node, &all_dbs) {
- struct db *db = node->data;
- ovsdb_trigger_wait(db->db, time_msec());
- }
- if (run_process) {
- process_wait(run_process);
- }
- if (exiting) {
- poll_immediate_wake();
- }
- poll_timer_wait_until(status_timer);
- poll_block();
- }
ovsdb_jsonrpc_server_destroy(jsonrpc);
- SHASH_FOR_EACH(node, &all_dbs) {
+ SHASH_FOR_EACH_SAFE(node, next, &all_dbs) {
struct db *db = node->data;
- ovsdb_destroy(db->db);
+ close_db(db);
+ shash_delete(&all_dbs, node);
}
sset_destroy(&remotes);
+ sset_destroy(&db_filenames);
unixctl_server_destroy(unixctl);
if (run_process && process_exited(run_process)) {
}
}
+ service_stop();
return 0;
}
+/* Returns true if 'filename' is known to be already open as a database,
+ * false if not.
+ *
+ * "False negatives" are possible. */
+static bool
+is_already_open(struct server_config *config OVS_UNUSED,
+ const char *filename OVS_UNUSED)
+{
+#ifndef _WIN32
+ struct stat s;
+
+ if (!stat(filename, &s)) {
+ struct shash_node *node;
+
+ SHASH_FOR_EACH (node, config->all_dbs) {
+ struct db *db = node->data;
+ struct stat s2;
+
+ if (!stat(db->filename, &s2)
+ && s.st_dev == s2.st_dev
+ && s.st_ino == s2.st_ino) {
+ return true;
+ }
+ }
+ }
+#endif /* !_WIN32 */
+
+ return false;
+}
+
+static void
+close_db(struct db *db)
+{
+ ovsdb_destroy(db->db);
+ free(db->filename);
+ free(db);
+}
+
static char *
open_db(struct server_config *config, const char *filename)
{
struct db *db;
char *error;
+ /* If we know that the file is already open, return a good error message.
+ * Otherwise, if the file is open, we'll fail later on with a harder to
+ * interpret file locking error. */
+ if (is_already_open(config, filename)) {
+ return xasprintf("%s: already open", filename);
+ }
+
db = xzalloc(sizeof *db);
db->filename = xstrdup(filename);
}
ovsdb_error_destroy(db_error);
- ovsdb_destroy(db->db);
- free(db->filename);
- free(db);
+ close_db(db);
return error;
}
return NULL;
}
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_db_column__(const struct shash *all_dbs,
const char *name_, char *name,
const struct db **dbp,
/* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_db_column(const struct shash *all_dbs,
const char *name_,
const struct db **dbp,
/* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_db_string_column(const struct shash *all_dbs,
const char *name,
const struct db **dbp,
&db, &table, &column);
if (retval) {
ds_put_format(errors, "%s\n", retval);
+ free(retval);
return NULL;
}
if (!VLOG_DROP_DBG(&rl)) {
char *type_name = ovsdb_type_to_english(&column->type);
VLOG_DBG("Table `%s' column `%s' has type %s, not expected "
- "key type %s, value type %s, max elements %zd.",
+ "key type %s, value type %s, max elements %"PRIuSIZE".",
schema->name, column_name, type_name,
ovsdb_atomic_type_to_string(key_type),
ovsdb_atomic_type_to_string(value_type),
ok = ovsdb_jsonrpc_server_remove_db(config->jsonrpc, db->db);
ovs_assert(ok);
- ovsdb_destroy(db->db);
+ close_db(db);
shash_delete(config->all_dbs, node);
- free(db->filename);
- free(db);
save_config(config);
unixctl_command_reply(conn, NULL);
OPT_UNIXCTL,
OPT_RUN,
OPT_BOOTSTRAP_CA_CERT,
- OPT_ENABLE_DUMMY,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS
};
static const struct option long_options[] = {
{"remote", required_argument, NULL, OPT_REMOTE},
{"unixctl", required_argument, NULL, OPT_UNIXCTL},
+#ifndef _WIN32
{"run", required_argument, NULL, OPT_RUN},
+#endif
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
DAEMON_LONG_OPTIONS,
{"private-key", required_argument, NULL, 'p'},
{"certificate", required_argument, NULL, 'c'},
{"ca-cert", required_argument, NULL, 'C'},
- {"enable-dummy", optional_argument, NULL, OPT_ENABLE_DUMMY},
{NULL, 0, NULL, 0},
};
- char *short_options = long_options_to_short_options(long_options);
+ char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
int argc = *argcp;
char **argv = *argvp;
bootstrap_ca_cert = true;
break;
- case OPT_ENABLE_DUMMY:
- dummy_enable(optarg && !strcmp(optarg, "override"));
- break;
-
case '?':
exit(EXIT_FAILURE);