value is printed on a separate line. Duplicates will be printed
multiple times.
.
+.IP "\fB-c\fR, \fB--changes\fR"
+.
+Logs all of the changes made to the configuration file in a ``unified
+diff''-like format. Only actual changes are logged, so that if, for
+example, a \fB--del-match\fR action did not match any key-value pairs,
+then nothing will be logged due to that action. Furthermore, only the
+net effects of changes are logged: if a key-value pair was deleted and
+then an identical key-value pair was added back, then nothing would be
+logged due to those changes.
+.
+This action logs changes that have taken effect at the point where it
+is inserted. Thus, if it is given before any other action, it will
+not log any changes. If \fB--changes\fR is given more than once,
+instances after the first log only the changes since the previous
+instance.
+.
.SH "SEE ALSO"
.BR vswitchd (8),
.BR vswitchd.conf (5)
#include "timeval.h"
#include "util.h"
+#define THIS_MODULE VLM_cfg_mod
+#include "vlog.h"
+
+/* Configuration when we first read the configuration file. */
+static struct svec orig_cfg = SVEC_EMPTY_INITIALIZER;
+
static void
usage(char *prog_name, int exit_code)
{
" -d, --del-entry=ENTRY delete ENTRY\n"
" -D, --del-section=KEY delete section matching KEY\n"
" --del-match=PATTERN delete entries matching shell PATTERN\n"
- " -q, --query=KEY return all entries matching KEY \n",
+ " -q, --query=KEY return all entries matching KEY\n"
+ " -c, --log-changes log changes up to this point\n",
prog_name);
exit(exit_code);
}
if (error) {
ovs_fatal(error, "could not lock configuration file\n");
}
+
+ cfg_get_all(&orig_cfg);
}
static void
printf("%s\n", vals.names[i]);
}
}
-
+
+static void
+log_diffs(void)
+{
+ struct svec new_cfg, removed, added;
+ size_t i;
+
+ svec_init(&new_cfg);
+ cfg_get_all(&new_cfg);
+ svec_diff(&orig_cfg, &new_cfg, &removed, NULL, &added);
+ if (removed.n || added.n) {
+ VLOG_INFO("configuration changes:");
+ for (i = 0; i < removed.n; i++) {
+ VLOG_INFO("-%s", removed.names[i]);
+ }
+ for (i = 0; i < added.n; i++) {
+ VLOG_INFO("+%s", added.names[i]);
+ }
+ } else {
+ VLOG_INFO("configuration unchanged");
+ }
+ svec_destroy(&added);
+ svec_destroy(&removed);
+ svec_swap(&new_cfg, &orig_cfg);
+ svec_destroy(&new_cfg);
+}
+
int main(int argc, char *argv[])
{
enum {
{"del-section", required_argument, 0, 'D'},
{"del-match", required_argument, 0, OPT_DEL_MATCH},
{"query", required_argument, 0, 'q'},
+ {"changes", no_argument, 0, 'c'},
+ {"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0},
};
set_program_name(argv[0]);
time_init();
+ vlog_init();
short_options = long_options_to_short_options(long_options);
for (;;) {
print_vals(optarg);
break;
+ case 'c':
+ log_diffs();
+ break;
+
case 'h':
usage(argv[0], EXIT_SUCCESS);
break;
+ case 'v':
+ vlog_set_verbosity(optarg);
+ break;
+
case '?':
exit(EXIT_FAILURE);