]>
Commit | Line | Data |
---|---|---|
f85f8ebb | 1 | /* |
a15fce8e | 2 | * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. |
f85f8ebb BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #include <config.h> | |
18 | #include <errno.h> | |
19 | #include <fcntl.h> | |
20 | #include <getopt.h> | |
21 | #include <signal.h> | |
22 | #include <stdlib.h> | |
23 | #include <string.h> | |
24 | ||
4e92542c | 25 | #include "column.h" |
f85f8ebb BP |
26 | #include "command-line.h" |
27 | #include "compiler.h" | |
e4476f74 | 28 | #include "dirs.h" |
3e8a2ad1 | 29 | #include "openvswitch/dynamic-string.h" |
8a777cf6 | 30 | #include "fatal-signal.h" |
bd06962a | 31 | #include "file.h" |
1e19e50e | 32 | #include "lockfile.h" |
41709ccc | 33 | #include "log.h" |
ee89ea7b | 34 | #include "openvswitch/json.h" |
f85f8ebb | 35 | #include "ovsdb.h" |
4e92542c | 36 | #include "ovsdb-data.h" |
f85f8ebb | 37 | #include "ovsdb-error.h" |
1e19e50e | 38 | #include "socket-util.h" |
f85f8ebb BP |
39 | #include "table.h" |
40 | #include "timeval.h" | |
41 | #include "util.h" | |
e6211adc | 42 | #include "openvswitch/vlog.h" |
5136ce49 | 43 | |
c6782bb0 BP |
44 | /* -m, --more: Verbosity level for "show-log" command output. */ |
45 | static int show_log_verbosity; | |
46 | ||
d6db7b3c LR |
47 | /* --role: RBAC role to use for "transact" and "query" commands. */ |
48 | static const char *rbac_role; | |
49 | ||
5f383751 | 50 | static const struct ovs_cmdl_command *get_all_commands(void); |
f85f8ebb | 51 | |
cab50449 | 52 | OVS_NO_RETURN static void usage(void); |
f85f8ebb BP |
53 | static void parse_options(int argc, char *argv[]); |
54 | ||
e4476f74 BP |
55 | static const char *default_db(void); |
56 | static const char *default_schema(void); | |
57 | ||
f85f8ebb BP |
58 | int |
59 | main(int argc, char *argv[]) | |
60 | { | |
1636c761 | 61 | struct ovs_cmdl_context ctx = { .argc = 0, }; |
f85f8ebb | 62 | set_program_name(argv[0]); |
f85f8ebb | 63 | parse_options(argc, argv); |
8a777cf6 | 64 | fatal_ignore_sigpipe(); |
1636c761 RB |
65 | ctx.argc = argc - optind; |
66 | ctx.argv = argv + optind; | |
67 | ovs_cmdl_run_command(&ctx, get_all_commands()); | |
f85f8ebb BP |
68 | return 0; |
69 | } | |
70 | ||
71 | static void | |
72 | parse_options(int argc, char *argv[]) | |
73 | { | |
d6db7b3c LR |
74 | enum { |
75 | OPT_RBAC_ROLE = UCHAR_MAX + 1 | |
76 | }; | |
07fc4ed3 | 77 | static const struct option long_options[] = { |
e3c17733 | 78 | {"more", no_argument, NULL, 'm'}, |
d6db7b3c | 79 | {"rbac-role", required_argument, NULL, OPT_RBAC_ROLE}, |
e3c17733 BP |
80 | {"verbose", optional_argument, NULL, 'v'}, |
81 | {"help", no_argument, NULL, 'h'}, | |
66fa2c88 | 82 | {"option", no_argument, NULL, 'o'}, |
e3c17733 BP |
83 | {"version", no_argument, NULL, 'V'}, |
84 | {NULL, 0, NULL, 0}, | |
f85f8ebb | 85 | }; |
5f383751 | 86 | char *short_options = ovs_cmdl_long_options_to_short_options(long_options); |
f85f8ebb BP |
87 | |
88 | for (;;) { | |
89 | int c; | |
90 | ||
91 | c = getopt_long(argc, argv, short_options, long_options, NULL); | |
92 | if (c == -1) { | |
93 | break; | |
94 | } | |
95 | ||
96 | switch (c) { | |
c6782bb0 BP |
97 | case 'm': |
98 | show_log_verbosity++; | |
99 | break; | |
100 | ||
d6db7b3c LR |
101 | case OPT_RBAC_ROLE: |
102 | rbac_role = optarg; | |
103 | break; | |
104 | ||
f85f8ebb BP |
105 | case 'h': |
106 | usage(); | |
107 | ||
66fa2c88 | 108 | case 'o': |
5f383751 | 109 | ovs_cmdl_print_options(long_options); |
66fa2c88 AW |
110 | exit(EXIT_SUCCESS); |
111 | ||
f85f8ebb | 112 | case 'V': |
55d5bb44 | 113 | ovs_print_version(0, 0); |
f85f8ebb BP |
114 | exit(EXIT_SUCCESS); |
115 | ||
116 | case 'v': | |
117 | vlog_set_verbosity(optarg); | |
118 | break; | |
119 | ||
120 | case '?': | |
121 | exit(EXIT_FAILURE); | |
122 | ||
123 | default: | |
124 | abort(); | |
125 | } | |
126 | } | |
127 | free(short_options); | |
128 | } | |
129 | ||
130 | static void | |
131 | usage(void) | |
132 | { | |
133 | printf("%s: Open vSwitch database management utility\n" | |
134 | "usage: %s [OPTIONS] COMMAND [ARG...]\n" | |
e4476f74 BP |
135 | " create [DB [SCHEMA]] create DB with the given SCHEMA\n" |
136 | " compact [DB [DST]] compact DB in-place (or to DST)\n" | |
137 | " convert [DB [SCHEMA [DST]]] convert DB to SCHEMA (to DST)\n" | |
138 | " db-version [DB] report version of schema used by DB\n" | |
139 | " db-cksum [DB] report checksum of schema used by DB\n" | |
140 | " schema-version [SCHEMA] report SCHEMA's schema version\n" | |
141 | " schema-cksum [SCHEMA] report SCHEMA's checksum\n" | |
142 | " query [DB] TRNS execute read-only transaction on DB\n" | |
143 | " transact [DB] TRNS execute read/write transaction on DB\n" | |
144 | " [-m]... show-log [DB] print DB's log entries\n" | |
145 | "The default DB is %s.\n" | |
146 | "The default SCHEMA is %s.\n", | |
147 | program_name, program_name, default_db(), default_schema()); | |
f85f8ebb | 148 | vlog_usage(); |
d6db7b3c LR |
149 | printf("\ |
150 | \nOther options:\n\ | |
151 | -m, --more increase show-log verbosity\n\ | |
152 | --rbac-role=ROLE RBAC role for transact and query commands\n\ | |
153 | -h, --help display this help message\n\ | |
154 | -V, --version display version information\n"); | |
f85f8ebb BP |
155 | exit(EXIT_SUCCESS); |
156 | } | |
e4476f74 BP |
157 | |
158 | static const char * | |
159 | default_db(void) | |
160 | { | |
161 | static char *db; | |
162 | if (!db) { | |
f973f2af | 163 | db = xasprintf("%s/conf.db", ovs_dbdir()); |
e4476f74 BP |
164 | } |
165 | return db; | |
166 | } | |
167 | ||
168 | static const char * | |
169 | default_schema(void) | |
170 | { | |
171 | static char *schema; | |
172 | if (!schema) { | |
173 | schema = xasprintf("%s/vswitch.ovsschema", ovs_pkgdatadir()); | |
174 | } | |
175 | return schema; | |
176 | } | |
f85f8ebb BP |
177 | \f |
178 | static struct json * | |
179 | parse_json(const char *s) | |
180 | { | |
181 | struct json *json = json_from_string(s); | |
182 | if (json->type == JSON_STRING) { | |
183 | ovs_fatal(0, "\"%s\": %s", s, json->u.string); | |
184 | } | |
185 | return json; | |
186 | } | |
187 | ||
188 | static void | |
189 | print_and_free_json(struct json *json) | |
190 | { | |
191 | char *string = json_to_string(json, JSSF_SORT); | |
192 | json_destroy(json); | |
193 | puts(string); | |
194 | free(string); | |
195 | } | |
196 | ||
197 | static void | |
198 | check_ovsdb_error(struct ovsdb_error *error) | |
199 | { | |
200 | if (error) { | |
201 | ovs_fatal(0, "%s", ovsdb_error_to_string(error)); | |
202 | } | |
203 | } | |
204 | \f | |
205 | static void | |
1636c761 | 206 | do_create(struct ovs_cmdl_context *ctx) |
f85f8ebb | 207 | { |
1636c761 RB |
208 | const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
209 | const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); | |
f85f8ebb | 210 | struct ovsdb_schema *schema; |
41709ccc | 211 | struct ovsdb_log *log; |
f85f8ebb BP |
212 | struct json *json; |
213 | ||
214 | /* Read schema from file and convert to JSON. */ | |
215 | check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); | |
216 | json = ovsdb_schema_to_json(schema); | |
90cc4071 | 217 | ovsdb_schema_destroy(schema); |
f85f8ebb BP |
218 | |
219 | /* Create database file. */ | |
7446f148 BP |
220 | check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_CREATE, |
221 | -1, &log)); | |
41709ccc BP |
222 | check_ovsdb_error(ovsdb_log_write(log, json)); |
223 | check_ovsdb_error(ovsdb_log_commit(log)); | |
224 | ovsdb_log_close(log); | |
f85f8ebb BP |
225 | |
226 | json_destroy(json); | |
227 | } | |
228 | ||
1e19e50e | 229 | static void |
a35ae81c | 230 | compact_or_convert(const char *src_name_, const char *dst_name_, |
1e19e50e BP |
231 | const struct ovsdb_schema *new_schema, |
232 | const char *comment) | |
233 | { | |
a35ae81c | 234 | char *src_name, *dst_name; |
1e19e50e BP |
235 | struct lockfile *src_lock; |
236 | struct lockfile *dst_lock; | |
a35ae81c | 237 | bool in_place = dst_name_ == NULL; |
1e19e50e BP |
238 | struct ovsdb *db; |
239 | int retval; | |
240 | ||
a35ae81c BP |
241 | /* Dereference symlinks for source and destination names. In the in-place |
242 | * case this ensures that, if the source name is a symlink, we replace its | |
243 | * target instead of replacing the symlink by a regular file. In the | |
244 | * non-in-place, this has the same effect for the destination name. */ | |
245 | src_name = follow_symlinks(src_name_); | |
246 | dst_name = (in_place | |
247 | ? xasprintf("%s.tmp", src_name) | |
248 | : follow_symlinks(dst_name_)); | |
249 | ||
aebfc869 | 250 | /* Lock the source, if we will be replacing it. */ |
1e19e50e | 251 | if (in_place) { |
4770e795 | 252 | retval = lockfile_lock(src_name, &src_lock); |
aebfc869 BP |
253 | if (retval) { |
254 | ovs_fatal(retval, "%s: failed to lock lockfile", src_name); | |
255 | } | |
1e19e50e BP |
256 | } |
257 | ||
aebfc869 | 258 | /* Get (temporary) destination and lock it. */ |
4770e795 | 259 | retval = lockfile_lock(dst_name, &dst_lock); |
1e19e50e BP |
260 | if (retval) { |
261 | ovs_fatal(retval, "%s: failed to lock lockfile", dst_name); | |
262 | } | |
263 | ||
264 | /* Save a copy. */ | |
265 | check_ovsdb_error(new_schema | |
266 | ? ovsdb_file_open_as_schema(src_name, new_schema, &db) | |
ada496b5 | 267 | : ovsdb_file_open(src_name, true, &db, NULL)); |
1e19e50e BP |
268 | check_ovsdb_error(ovsdb_file_save_copy(dst_name, false, comment, db)); |
269 | ovsdb_destroy(db); | |
270 | ||
271 | /* Replace source. */ | |
272 | if (in_place) { | |
10c119c3 GS |
273 | #ifdef _WIN32 |
274 | unlink(src_name); | |
275 | #endif | |
1e19e50e BP |
276 | if (rename(dst_name, src_name)) { |
277 | ovs_fatal(errno, "failed to rename \"%s\" to \"%s\"", | |
278 | dst_name, src_name); | |
279 | } | |
280 | fsync_parent_dir(dst_name); | |
1e19e50e BP |
281 | lockfile_unlock(src_lock); |
282 | } | |
283 | ||
284 | lockfile_unlock(dst_lock); | |
e49190c4 | 285 | |
a35ae81c BP |
286 | free(src_name); |
287 | free(dst_name); | |
1e19e50e BP |
288 | } |
289 | ||
290 | static void | |
1636c761 | 291 | do_compact(struct ovs_cmdl_context *ctx) |
1e19e50e | 292 | { |
1636c761 RB |
293 | const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
294 | const char *target = ctx->argc >= 3 ? ctx->argv[2] : NULL; | |
e4476f74 | 295 | |
8a07709c | 296 | compact_or_convert(db, target, NULL, "compacted by ovsdb-tool "VERSION); |
1e19e50e BP |
297 | } |
298 | ||
299 | static void | |
1636c761 | 300 | do_convert(struct ovs_cmdl_context *ctx) |
1e19e50e | 301 | { |
1636c761 RB |
302 | const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
303 | const char *schema = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); | |
304 | const char *target = ctx->argc >= 4 ? ctx->argv[3] : NULL; | |
1e19e50e BP |
305 | struct ovsdb_schema *new_schema; |
306 | ||
e4476f74 BP |
307 | check_ovsdb_error(ovsdb_schema_from_file(schema, &new_schema)); |
308 | compact_or_convert(db, target, new_schema, | |
8a07709c | 309 | "converted by ovsdb-tool "VERSION); |
1e19e50e BP |
310 | ovsdb_schema_destroy(new_schema); |
311 | } | |
312 | ||
403e3a25 | 313 | static void |
1636c761 | 314 | do_needs_conversion(struct ovs_cmdl_context *ctx) |
403e3a25 | 315 | { |
1636c761 RB |
316 | const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
317 | const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); | |
403e3a25 BP |
318 | struct ovsdb_schema *schema1, *schema2; |
319 | ||
320 | check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema1)); | |
321 | check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema2)); | |
322 | puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes"); | |
323 | ovsdb_schema_destroy(schema1); | |
324 | ovsdb_schema_destroy(schema2); | |
325 | } | |
326 | ||
8159b984 | 327 | static void |
1636c761 | 328 | do_db_version(struct ovs_cmdl_context *ctx) |
8159b984 | 329 | { |
1636c761 | 330 | const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
e1ebc8ce | 331 | struct ovsdb_schema *schema; |
8159b984 | 332 | |
e1ebc8ce BP |
333 | check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema)); |
334 | puts(schema->version); | |
335 | ovsdb_schema_destroy(schema); | |
8159b984 BP |
336 | } |
337 | ||
6aa09313 | 338 | static void |
1636c761 | 339 | do_db_cksum(struct ovs_cmdl_context *ctx) |
6aa09313 | 340 | { |
1636c761 | 341 | const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
6aa09313 BP |
342 | struct ovsdb_schema *schema; |
343 | ||
344 | check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema)); | |
345 | puts(schema->cksum); | |
346 | ovsdb_schema_destroy(schema); | |
347 | } | |
348 | ||
8159b984 | 349 | static void |
1636c761 | 350 | do_schema_version(struct ovs_cmdl_context *ctx) |
8159b984 | 351 | { |
1636c761 | 352 | const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema(); |
8159b984 BP |
353 | struct ovsdb_schema *schema; |
354 | ||
355 | check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); | |
356 | puts(schema->version); | |
357 | ovsdb_schema_destroy(schema); | |
358 | } | |
359 | ||
6aa09313 | 360 | static void |
1636c761 | 361 | do_schema_cksum(struct ovs_cmdl_context *ctx) |
6aa09313 | 362 | { |
1636c761 | 363 | const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema(); |
6aa09313 BP |
364 | struct ovsdb_schema *schema; |
365 | ||
366 | check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); | |
367 | puts(schema->cksum); | |
368 | ovsdb_schema_destroy(schema); | |
369 | } | |
370 | ||
f85f8ebb | 371 | static void |
e4476f74 | 372 | transact(bool read_only, int argc, char *argv[]) |
f85f8ebb | 373 | { |
e4476f74 BP |
374 | const char *db_file_name = argc >= 3 ? argv[1] : default_db(); |
375 | const char *transaction = argv[argc - 1]; | |
f85f8ebb BP |
376 | struct json *request, *result; |
377 | struct ovsdb *db; | |
378 | ||
ada496b5 | 379 | check_ovsdb_error(ovsdb_file_open(db_file_name, read_only, &db, NULL)); |
f85f8ebb BP |
380 | |
381 | request = parse_json(transaction); | |
d6db7b3c | 382 | result = ovsdb_execute(db, NULL, request, false, rbac_role, NULL, 0, NULL); |
f85f8ebb BP |
383 | json_destroy(request); |
384 | ||
385 | print_and_free_json(result); | |
386 | ovsdb_destroy(db); | |
387 | } | |
388 | ||
389 | static void | |
1636c761 | 390 | do_query(struct ovs_cmdl_context *ctx) |
f85f8ebb | 391 | { |
1636c761 | 392 | transact(true, ctx->argc, ctx->argv); |
f85f8ebb BP |
393 | } |
394 | ||
395 | static void | |
1636c761 | 396 | do_transact(struct ovs_cmdl_context *ctx) |
f85f8ebb | 397 | { |
1636c761 | 398 | transact(false, ctx->argc, ctx->argv); |
f85f8ebb BP |
399 | } |
400 | ||
c6782bb0 | 401 | static void |
4e92542c BP |
402 | print_db_changes(struct shash *tables, struct shash *names, |
403 | const struct ovsdb_schema *schema) | |
c6782bb0 BP |
404 | { |
405 | struct shash_node *n1; | |
406 | ||
407 | SHASH_FOR_EACH (n1, tables) { | |
408 | const char *table = n1->name; | |
4e92542c | 409 | struct ovsdb_table_schema *table_schema; |
c6782bb0 BP |
410 | struct json *rows = n1->data; |
411 | struct shash_node *n2; | |
412 | ||
413 | if (n1->name[0] == '_' || rows->type != JSON_OBJECT) { | |
414 | continue; | |
415 | } | |
416 | ||
4e92542c | 417 | table_schema = shash_find_data(&schema->tables, table); |
c6782bb0 BP |
418 | SHASH_FOR_EACH (n2, json_object(rows)) { |
419 | const char *row_uuid = n2->name; | |
420 | struct json *columns = n2->data; | |
421 | struct shash_node *n3; | |
422 | char *old_name, *new_name; | |
423 | bool free_new_name = false; | |
424 | ||
425 | old_name = new_name = shash_find_data(names, row_uuid); | |
426 | if (columns->type == JSON_OBJECT) { | |
427 | struct json *new_name_json; | |
428 | ||
429 | new_name_json = shash_find_data(json_object(columns), "name"); | |
430 | if (new_name_json) { | |
431 | new_name = json_to_string(new_name_json, JSSF_SORT); | |
432 | free_new_name = true; | |
433 | } | |
434 | } | |
435 | ||
436 | printf("\ttable %s", table); | |
437 | ||
438 | if (!old_name) { | |
439 | if (new_name) { | |
a0a15a00 | 440 | printf(" insert row %s (%.8s):\n", new_name, row_uuid); |
c6782bb0 BP |
441 | } else { |
442 | printf(" insert row %.8s:\n", row_uuid); | |
443 | } | |
444 | } else { | |
a0a15a00 | 445 | printf(" row %s (%.8s):\n", old_name, row_uuid); |
c6782bb0 BP |
446 | } |
447 | ||
448 | if (columns->type == JSON_OBJECT) { | |
449 | if (show_log_verbosity > 1) { | |
450 | SHASH_FOR_EACH (n3, json_object(columns)) { | |
451 | const char *column = n3->name; | |
4e92542c | 452 | const struct ovsdb_column *column_schema; |
c6782bb0 | 453 | struct json *value = n3->data; |
4e92542c BP |
454 | char *value_string = NULL; |
455 | ||
456 | column_schema = | |
457 | (table_schema | |
458 | ? shash_find_data(&table_schema->columns, column) | |
459 | : NULL); | |
460 | if (column_schema) { | |
4e92542c | 461 | const struct ovsdb_type *type; |
a15fce8e | 462 | struct ovsdb_error *error; |
4e92542c BP |
463 | struct ovsdb_datum datum; |
464 | ||
465 | type = &column_schema->type; | |
466 | error = ovsdb_datum_from_json(&datum, type, | |
467 | value, NULL); | |
468 | if (!error) { | |
469 | struct ds s; | |
470 | ||
471 | ds_init(&s); | |
472 | ovsdb_datum_to_string(&datum, type, &s); | |
473 | value_string = ds_steal_cstr(&s); | |
a15fce8e BP |
474 | } else { |
475 | ovsdb_error_destroy(error); | |
4e92542c BP |
476 | } |
477 | } | |
478 | if (!value_string) { | |
479 | value_string = json_to_string(value, JSSF_SORT); | |
480 | } | |
c6782bb0 BP |
481 | printf("\t\t%s=%s\n", column, value_string); |
482 | free(value_string); | |
483 | } | |
484 | } | |
485 | if (!old_name | |
486 | || (new_name != old_name && strcmp(old_name, new_name))) { | |
487 | if (old_name) { | |
488 | shash_delete(names, shash_find(names, row_uuid)); | |
489 | free(old_name); | |
490 | } | |
491 | shash_add(names, row_uuid, (new_name | |
492 | ? xstrdup(new_name) | |
493 | : xmemdup0(row_uuid, 8))); | |
494 | } | |
495 | } else if (columns->type == JSON_NULL) { | |
b932d88b BP |
496 | struct shash_node *node; |
497 | ||
c6782bb0 | 498 | printf("\t\tdelete row\n"); |
b932d88b BP |
499 | node = shash_find(names, row_uuid); |
500 | if (node) { | |
501 | shash_delete(names, node); | |
502 | } | |
c6782bb0 BP |
503 | free(old_name); |
504 | } | |
505 | ||
506 | if (free_new_name) { | |
507 | free(new_name); | |
508 | } | |
509 | } | |
510 | } | |
511 | } | |
512 | ||
722f6301 | 513 | static void |
1636c761 | 514 | do_show_log(struct ovs_cmdl_context *ctx) |
722f6301 | 515 | { |
1636c761 | 516 | const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); |
c6782bb0 | 517 | struct shash names; |
722f6301 | 518 | struct ovsdb_log *log; |
4e92542c | 519 | struct ovsdb_schema *schema; |
722f6301 BP |
520 | unsigned int i; |
521 | ||
7446f148 BP |
522 | check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_READ_ONLY, |
523 | -1, &log)); | |
c6782bb0 | 524 | shash_init(&names); |
4e92542c | 525 | schema = NULL; |
722f6301 BP |
526 | for (i = 0; ; i++) { |
527 | struct json *json; | |
528 | ||
529 | check_ovsdb_error(ovsdb_log_read(log, &json)); | |
530 | if (!json) { | |
531 | break; | |
532 | } | |
533 | ||
534 | printf("record %u:", i); | |
4e92542c BP |
535 | if (i == 0) { |
536 | check_ovsdb_error(ovsdb_schema_from_json(json, &schema)); | |
537 | printf(" \"%s\" schema, version=\"%s\", cksum=\"%s\"\n", | |
538 | schema->name, schema->version, schema->cksum); | |
539 | } else if (json->type == JSON_OBJECT) { | |
722f6301 BP |
540 | struct json *date, *comment; |
541 | ||
542 | date = shash_find_data(json_object(json), "_date"); | |
543 | if (date && date->type == JSON_INTEGER) { | |
1ff1065c PI |
544 | long long int t = json_integer(date); |
545 | char *s; | |
546 | ||
547 | if (t < INT32_MAX) { | |
548 | /* Older versions of ovsdb wrote timestamps in seconds. */ | |
549 | t *= 1000; | |
550 | } | |
551 | ||
57093462 | 552 | s = xastrftime_msec(" %Y-%m-%d %H:%M:%S.###", t, true); |
3e78870d BP |
553 | fputs(s, stdout); |
554 | free(s); | |
722f6301 BP |
555 | } |
556 | ||
557 | comment = shash_find_data(json_object(json), "_comment"); | |
558 | if (comment && comment->type == JSON_STRING) { | |
559 | printf(" \"%s\"", json_string(comment)); | |
560 | } | |
c6782bb0 BP |
561 | |
562 | if (i > 0 && show_log_verbosity > 0) { | |
563 | putchar('\n'); | |
4e92542c | 564 | print_db_changes(json_object(json), &names, schema); |
c6782bb0 | 565 | } |
722f6301 BP |
566 | } |
567 | json_destroy(json); | |
568 | putchar('\n'); | |
569 | } | |
c6782bb0 | 570 | |
400eb935 | 571 | ovsdb_log_close(log); |
4e92542c | 572 | ovsdb_schema_destroy(schema); |
c6782bb0 | 573 | /* XXX free 'names'. */ |
722f6301 BP |
574 | } |
575 | ||
f85f8ebb | 576 | static void |
1636c761 | 577 | do_help(struct ovs_cmdl_context *ctx OVS_UNUSED) |
f85f8ebb BP |
578 | { |
579 | usage(); | |
580 | } | |
581 | ||
451de37e | 582 | static void |
1636c761 | 583 | do_list_commands(struct ovs_cmdl_context *ctx OVS_UNUSED) |
451de37e | 584 | { |
5f383751 | 585 | ovs_cmdl_print_commands(get_all_commands()); |
451de37e AW |
586 | } |
587 | ||
5f383751 | 588 | static const struct ovs_cmdl_command all_commands[] = { |
1f4a7252 RM |
589 | { "create", "[db [schema]]", 0, 2, do_create, OVS_RW }, |
590 | { "compact", "[db [dst]]", 0, 2, do_compact, OVS_RW }, | |
591 | { "convert", "[db [schema [dst]]]", 0, 3, do_convert, OVS_RW }, | |
592 | { "needs-conversion", NULL, 0, 2, do_needs_conversion, OVS_RO }, | |
593 | { "db-version", "[db]", 0, 1, do_db_version, OVS_RO }, | |
594 | { "db-cksum", "[db]", 0, 1, do_db_cksum, OVS_RO }, | |
595 | { "schema-version", "[schema]", 0, 1, do_schema_version, OVS_RO }, | |
596 | { "schema-cksum", "[schema]", 0, 1, do_schema_cksum, OVS_RO }, | |
597 | { "query", "[db] trns", 1, 2, do_query, OVS_RO }, | |
598 | { "transact", "[db] trns", 1, 2, do_transact, OVS_RO }, | |
599 | { "show-log", "[db]", 0, 1, do_show_log, OVS_RO }, | |
600 | { "help", NULL, 0, INT_MAX, do_help, OVS_RO }, | |
601 | { "list-commands", NULL, 0, INT_MAX, do_list_commands, OVS_RO }, | |
602 | { NULL, NULL, 0, 0, NULL, OVS_RO }, | |
f85f8ebb | 603 | }; |
3815d6c2 | 604 | |
5f383751 | 605 | static const struct ovs_cmdl_command *get_all_commands(void) |
3815d6c2 LS |
606 | { |
607 | return all_commands; | |
608 | } |