/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* used for LOG_LOCAL0. */
BUILD_ASSERT_DECL(LOG_LOCAL0 == (16 << 3));
-/* The log modules. */
-struct ovs_list vlog_modules = OVS_LIST_INITIALIZER(&vlog_modules);
-
/* Protects the 'pattern' in all "struct destination"s, so that a race between
* changing and reading the pattern does not cause an access to freed
* memory. */
*
* All of the following is protected by 'log_file_mutex', which nests inside
* pattern_rwlock. */
-static struct ovs_mutex log_file_mutex = OVS_MUTEX_INITIALIZER;
-static char *log_file_name OVS_GUARDED_BY(log_file_mutex);
+static struct ovs_mutex log_file_mutex OVS_ACQ_AFTER(pattern_rwlock)
+ = OVS_MUTEX_INITIALIZER;
+static char *log_file_name OVS_GUARDED_BY(log_file_mutex) = NULL;
static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1;
static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
static bool log_async OVS_GUARDED_BY(log_file_mutex);
static struct syslogger *syslogger = NULL;
+/* The log modules. */
+static struct ovs_list vlog_modules OVS_GUARDED_BY(log_file_mutex)
+ = OVS_LIST_INITIALIZER(&vlog_modules);
+
/* Syslog export configuration. */
static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
return i;
}
-void vlog_insert_module(struct ovs_list *vlog)
+void
+vlog_insert_module(struct ovs_list *vlog)
{
+ ovs_mutex_lock(&log_file_mutex);
list_insert(&vlog_modules, vlog);
+ ovs_mutex_unlock(&log_file_mutex);
}
/* Returns the name for logging module 'module'. */
{
struct vlog_module *mp;
+ ovs_mutex_lock(&log_file_mutex);
LIST_FOR_EACH (mp, list, &vlog_modules) {
if (!strcasecmp(name, mp->name)) {
+ ovs_mutex_unlock(&log_file_mutex);
return mp;
}
}
+ ovs_mutex_unlock(&log_file_mutex);
return NULL;
}
}
}
+#ifndef _WIN32
+/* In case a log file exists, change its owner to new 'user' and 'group'.
+ *
+ * This is useful for handling cases where the --log-file option is
+ * specified ahead of the --user option. */
+void
+vlog_change_owner_unix(uid_t user, gid_t group)
+{
+ struct ds err = DS_EMPTY_INITIALIZER;
+ int error;
+
+ ovs_mutex_lock(&log_file_mutex);
+ error = log_file_name ? chown(log_file_name, user, group) : 0;
+ if (error) {
+ /* Build the error message. We can not call VLOG_FATAL directly
+ * here because VLOG_FATAL() will try again to to acquire
+ * 'log_file_mutex' lock, causing deadlock.
+ */
+ ds_put_format(&err, "Failed to change %s ownership: %s.",
+ log_file_name, ovs_strerror(errno));
+ }
+ ovs_mutex_unlock(&log_file_mutex);
+
+ if (error) {
+ VLOG_FATAL("%s", ds_steal_cstr(&err));
+ }
+}
+#endif
+
/* Set debugging levels. Returns null if successful, otherwise an error
* message that the caller must free(). */
char *
free(msg);
}
+static void
+vlog_unixctl_list_pattern(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+{
+ char *msg;
+
+ msg = vlog_get_patterns();
+ unixctl_command_reply(conn, msg);
+ free(msg);
+}
+
static void
vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
}
}
+static void
+vlog_unixctl_close(struct unixctl_conn *conn, int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
+{
+ ovs_mutex_lock(&log_file_mutex);
+ if (log_fd >= 0) {
+ close(log_fd);
+ log_fd = -1;
+
+ async_append_destroy(log_writer);
+ log_writer = NULL;
+
+ struct vlog_module *mp;
+ LIST_FOR_EACH (mp, list, &vlog_modules) {
+ update_min_level(mp);
+ }
+ }
+ ovs_mutex_unlock(&log_file_mutex);
+
+ unixctl_command_reply(conn, NULL);
+}
+
static void
set_all_rate_limits(bool enable)
{
struct vlog_module *mp;
+ ovs_mutex_lock(&log_file_mutex);
LIST_FOR_EACH (mp, list, &vlog_modules) {
mp->honor_rate_limits = enable;
}
+ ovs_mutex_unlock(&log_file_mutex);
}
static void
if (ovsthread_once_start(&once)) {
long long int now;
int facility;
+ bool print_syslog_target_deprecation;
/* Do initialization work that needs to be done before any logging
* occurs. We want to keep this really minimal because any attempt to
1, INT_MAX, vlog_unixctl_set, NULL);
unixctl_command_register("vlog/list", "", 0, 0, vlog_unixctl_list,
NULL);
+ unixctl_command_register("vlog/list-pattern", "", 0, 0,
+ vlog_unixctl_list_pattern, NULL);
unixctl_command_register("vlog/enable-rate-limit", "[module]...",
0, INT_MAX, vlog_enable_rate_limit, NULL);
unixctl_command_register("vlog/disable-rate-limit", "[module]...",
0, INT_MAX, vlog_disable_rate_limit, NULL);
unixctl_command_register("vlog/reopen", "", 0, 0,
vlog_unixctl_reopen, NULL);
+ unixctl_command_register("vlog/close", "", 0, 0,
+ vlog_unixctl_close, NULL);
+
+ ovs_rwlock_rdlock(&pattern_rwlock);
+ print_syslog_target_deprecation = syslog_fd >= 0;
+ ovs_rwlock_unlock(&pattern_rwlock);
+
+ if (print_syslog_target_deprecation) {
+ VLOG_WARN("--syslog-target flag is deprecated, use "
+ "--syslog-method instead");
+ }
}
}
ds_put_format(&s, " console syslog file\n");
ds_put_format(&s, " ------- ------ ------\n");
+ ovs_mutex_lock(&log_file_mutex);
LIST_FOR_EACH (mp, list, &vlog_modules) {
struct ds line;
svec_add_nocopy(&lines, ds_steal_cstr(&line));
}
+ ovs_mutex_unlock(&log_file_mutex);
svec_sort(&lines);
SVEC_FOR_EACH (i, line, &lines) {
return ds_cstr(&s);
}
+/* Returns as a string current logging patterns for each destination.
+ * This string must be released by caller. */
+char *
+vlog_get_patterns(void)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ enum vlog_destination destination;
+
+ ovs_rwlock_rdlock(&pattern_rwlock);
+ ds_put_format(&ds, " prefix format\n");
+ ds_put_format(&ds, " ------ ------\n");
+
+ for (destination = 0; destination < VLF_N_DESTINATIONS; destination++) {
+ struct destination *f = &destinations[destination];
+ const char *prefix = "none";
+
+ if (destination == VLF_SYSLOG && syslogger) {
+ prefix = syslog_get_prefix(syslogger);
+ }
+ ds_put_format(&ds, "%-7s %-32s %s\n", f->name, prefix, f->pattern);
+ }
+ ovs_rwlock_unlock(&pattern_rwlock);
+
+ return ds_cstr(&ds);
+}
+
/* Returns true if a log message emitted for the given 'module' and 'level'
* would cause some log output, false if that module and level are completely
* disabled. */