Message ID | 20180220095950.23462-2-viktor.prutyanov@virtuozzo.com |
---|---|
State | Changes Requested |
Headers | show |
Series | dumpe2fs: add JSON output format | expand |
Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> writes: Looks good. Acked-by: Dmitry Monakhov <dmonakhov@openvz.org> > This patch adds JSON objects and lists and methods to print them > > Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> > --- > lib/support/Makefile.in | 7 +- > lib/support/json-out.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++ > lib/support/json-out.h | 69 ++++++++++ > misc/dumpe2fs.c | 17 ++- > 4 files changed, 416 insertions(+), 3 deletions(-) > create mode 100644 lib/support/json-out.c > create mode 100644 lib/support/json-out.h > > diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in > index 40206b74..42fa3324 100644 > --- a/lib/support/Makefile.in > +++ b/lib/support/Makefile.in > @@ -22,7 +22,8 @@ OBJS= cstring.o \ > quotaio.o \ > quotaio_v2.o \ > quotaio_tree.o \ > - dict.o > + dict.o \ > + json-out.o > > SRCS= $(srcdir)/argv_parse.c \ > $(srcdir)/cstring.c \ > @@ -35,7 +36,8 @@ SRCS= $(srcdir)/argv_parse.c \ > $(srcdir)/quotaio.c \ > $(srcdir)/quotaio_tree.c \ > $(srcdir)/quotaio_v2.c \ > - $(srcdir)/dict.c > + $(srcdir)/dict.c \ > + $(srcdir)/json-out.c > > LIBRARY= libsupport > LIBDIR= support > @@ -165,3 +167,4 @@ quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ > $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h > dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ > $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h > +json-out.o: $(srcdir)/json-out.c $(srcdir)/json-out.h > diff --git a/lib/support/json-out.c b/lib/support/json-out.c > new file mode 100644 > index 00000000..8c822f35 > --- /dev/null > +++ b/lib/support/json-out.c > @@ -0,0 +1,326 @@ > +/* > + * json-out.c -- JSON output > + * > + * Copyright (c) 2018 Virtuozzo International GmbH > + * > + * %Begin-Header% > + * This file may be redistributed under the terms of the GNU Public > + * License. > + * %End-Header% > + */ > + > +#include <stdio.h> > +#include <string.h> > +#include <stdlib.h> > +#include <stdarg.h> > + > +#include "json-out.h" > + > +static void *xmalloc(size_t size) > +{ > + void *p = malloc(size); > + > + if (!p) > + exit(1); > + > + return p; > +} > + > +static void *xstrdup(const char *str) > +{ > + size_t size = strlen(str) + 1; > + char *p = xmalloc(size); > + > + return strcpy(p, str); > +} > + > +struct json_list *json_list_create(enum json_val_type type) > +{ > + struct json_list *list = xmalloc(sizeof(struct json_list)); > + > + list->node = NULL; > + list->type = type; > + > + return list; > +} > + > +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type) > +{ > + struct json_list *list = json_list_create(type); > + > + json_obj_add_list(parent_obj, key, list); > + > + return list; > +} > + > +void json_list_delete(struct json_list *list) > +{ > + struct json_list_node *node = list->node, *next; > + > + while (node) { > + switch (list->type) { > + case JSON_VAL_STRING: > + free(node->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_delete(node->val.list); > + break; > + case JSON_VAL_OBJECT: > + json_obj_delete(node->val.obj); > + break; > + default: > + break; > + } > + next = node->next; > + free(node); > + node = next; > + } > + free(list); > +} > + > +struct json_obj *json_obj_create(void) > +{ > + struct json_obj *obj = xmalloc(sizeof(struct json_obj)); > + > + obj->pair = NULL; > + > + return obj; > +} > + > +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key) > +{ > + struct json_obj *obj = json_obj_create(); > + > + json_obj_add_obj(parent_obj, key, obj); > + > + return obj; > +} > + > +static void json_pair_delete(struct json_pair *pair) > +{ > + switch (pair->type) > + { > + case JSON_VAL_STRING: > + free(pair->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_delete(pair->val.list); > + break; > + case JSON_VAL_OBJECT: > + json_obj_delete(pair->val.obj); > + break; > + default: > + break; > + } > + free(pair->key); > + free(pair); > +} > + > +void json_obj_delete(struct json_obj *obj) > +{ > + struct json_pair *pair = obj->pair, *next; > + > + while (pair) { > + next = pair->next; > + json_pair_delete(pair); > + pair = next; > + } > + free(obj); > +} > + > +void json_obj_delete_pair(struct json_obj *obj, char *key) > +{ > + struct json_pair *pair = obj->pair, *next, *prev = NULL; > + > + while (pair) { > + next = pair->next; > + if (!strcmp(pair->key, key)) { > + json_pair_delete(pair); > + if (prev) > + prev->next = next; > + else > + obj->pair = next; > + break; > + } > + prev = pair; > + pair = next; > + } > +} > + > +static struct json_list_node *json_list_add_node(struct json_list *list) > +{ > + struct json_list_node *new_node = xmalloc(sizeof(struct json_list_node)); > + > + new_node->next = NULL; > + > + if (list->node) { > + struct json_list_node *node; > + > + for (node = list->node; node && node->next; node = node->next); > + node->next = new_node; > + } else > + list->node = new_node; > + > + return new_node; > +} > + > +void json_list_add_str(struct json_list *list, const char *str) > +{ > + struct json_list_node *new_node = json_list_add_node(list); > + > + new_node->val.str = xstrdup(str); > +} > + > +void json_list_add_obj(struct json_list *list, struct json_obj *obj) > +{ > + struct json_list_node *new_node = json_list_add_node(list); > + > + new_node->val.obj = obj; > +} > + > +static struct json_pair *json_obj_add_pair(struct json_obj *obj, const char *key, enum json_val_type type) > +{ > + struct json_pair *new_pair = xmalloc(sizeof(struct json_pair)); > + new_pair->key = xstrdup(key); > + new_pair->next = NULL; > + new_pair->type = type; > + > + if (obj->pair) { > + struct json_pair *pair; > + > + for (pair = obj->pair; pair && pair->next; pair = pair->next); > + pair->next = new_pair; > + } else > + obj->pair = new_pair; > + > + return new_pair; > +} > + > +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str) > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_STRING); > + > + new_pair->val.str = xstrdup(str); > +} > + > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...) > +{ > + va_list ap; > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > +} > + > +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...) > +{ > + va_list ap; > + char *buf = malloc(size); > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > + free(buf); > +} > + > +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list) > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_LIST); > + > + new_pair->val.list = list; > +} > + > +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj) > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_OBJECT); > + > + new_pair->val.obj = new_obj; > +} > + > +static void json_pair_print_json(struct json_pair *pair, int ind_lvl); > +static void json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl); > + > +static void > +print_ind(int ind_lvl) > +{ > + int i; > + > + putchar('\n'); > + for (i = 0; i < ind_lvl; i++) > + fputs(" ", stdout); > +} > + > +void json_obj_print_json(struct json_obj *obj, int ind_lvl) > +{ > + struct json_pair *pair; > + > + printf("{"); > + for (pair = obj->pair; pair; pair = pair->next) { > + json_pair_print_json(pair, ind_lvl+1); > + if (pair->next) > + printf(", "); > + } > + if (obj->pair) /* Do not indent if object was empty */ > + print_ind(ind_lvl); > + printf("}"); > +} > + > +void json_list_print_json(struct json_list *list, int ind_lvl) > +{ > + struct json_list_node *node; > + > + printf("["); > + for (node = list->node; node; node = node->next) { > + json_list_node_print_json(node, list->type, ind_lvl+1); > + if (node->next) > + printf(", "); > + } > + if (list->node) /* Do not indent if list was empty */ > + print_ind(ind_lvl); > + printf("]"); > +} > + > +static void > +json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl) > +{ > + print_ind(ind_lvl); > + switch (type) { > + case JSON_VAL_STRING: > + printf("\"%s\"", node->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_print_json(node->val.list, ind_lvl); > + break; > + case JSON_VAL_OBJECT: > + json_obj_print_json(node->val.obj, ind_lvl); > + break; > + case JSON_VAL_FLAG: > + printf("%s", node->val.flag ? "true" : "false"); > + break; > + default: > + break; > + } > +} > + > +static void json_pair_print_json(struct json_pair *pair, int ind_lvl) > +{ > + print_ind(ind_lvl); > + printf("\"%s\": ", pair->key); > + switch (pair->type) { > + case JSON_VAL_STRING: > + printf("\"%s\"", pair->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_print_json(pair->val.list, ind_lvl); > + break; > + case JSON_VAL_OBJECT: > + json_obj_print_json(pair->val.obj, ind_lvl); > + break; > + default: > + break; > + } > +} > diff --git a/lib/support/json-out.h b/lib/support/json-out.h > new file mode 100644 > index 00000000..0132bd2c > --- /dev/null > +++ b/lib/support/json-out.h > @@ -0,0 +1,69 @@ > +/* > + * json-out.h -- JSON output > + * > + * Copyright (c) 2018 Virtuozzo International GmbH > + * > + * %Begin-Header% > + * This file may be redistributed under the terms of the GNU Public > + * License. > + * %End-Header% > + */ > + > +#ifndef H_JSON_OUT > +#define H_JSON_OUT > + > +enum json_val_type { > + JSON_VAL_STRING, > + JSON_VAL_OBJECT, > + JSON_VAL_LIST, > + JSON_VAL_FLAG > +}; > + > +struct json_obj { > + struct json_pair *pair; > +}; > + > +union json_val { > + char *str; > + struct json_obj *obj; > + struct json_list *list; > + char flag; > +}; > + > +struct json_pair { > + char *key; > + enum json_val_type type; > + union json_val val; > + struct json_pair *next; > +}; > + > +struct json_list { > + enum json_val_type type; > + struct json_list_node *node; > +}; > + > +struct json_list_node { > + union json_val val; > + struct json_list_node *next; > +}; > + > +struct json_obj *json_obj_create(void); > +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key); > +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str); > +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list); > +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj); > +void json_obj_add_flag(struct json_obj *obj, const char *key, char flag); > +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...); > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...); > +void json_obj_print_json(struct json_obj *obj, int ind_lvl); > +void json_obj_delete_pair(struct json_obj *obj, char *key); > +void json_obj_delete(struct json_obj *obj); > + > +struct json_list *json_list_create(enum json_val_type type); > +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type); > +void json_list_add_str(struct json_list *list, const char *str); > +void json_list_add_obj(struct json_list *list, struct json_obj *obj); > +void json_list_print_json(struct json_list *list, int ind_lvl); > +void json_list_delete(struct json_list *list); > + > +#endif > diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c > index 395ea9ee..ca9953a1 100644 > --- a/misc/dumpe2fs.c > +++ b/misc/dumpe2fs.c > @@ -607,7 +607,12 @@ try_open_again: > goto just_descriptors; > list_super (fs->super); > if (ext2fs_has_feature_journal_dev(fs->super)) { > - print_journal_information(fs); > + print_journal_information(fs, dump_obj); > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > exit(0); > } > @@ -616,6 +621,11 @@ try_open_again: > print_inline_journal_information(fs); > list_bad_blocks(fs, 0); > if (header_only) { > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > exit (0); > } > @@ -636,6 +646,11 @@ just_descriptors: > error_message(retval)); > } > } > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > remove_error_table(&et_ext2_error_table); > exit (0); > -- > 2.14.1
On Tue, 20 Feb 2018 12:59:46 +0300 Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> wrote: ping > This patch adds JSON objects and lists and methods to print them > > Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> > --- > lib/support/Makefile.in | 7 +- > lib/support/json-out.c | 326 > ++++++++++++++++++++++++++++++++++++++++++++++++ > lib/support/json-out.h | 69 ++++++++++ misc/dumpe2fs.c | > 17 ++- 4 files changed, 416 insertions(+), 3 deletions(-) > create mode 100644 lib/support/json-out.c > create mode 100644 lib/support/json-out.h > > diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in > index 40206b74..42fa3324 100644 > --- a/lib/support/Makefile.in > +++ b/lib/support/Makefile.in > @@ -22,7 +22,8 @@ OBJS= cstring.o \ > quotaio.o \ > quotaio_v2.o \ > quotaio_tree.o \ > - dict.o > + dict.o \ > + json-out.o > > SRCS= $(srcdir)/argv_parse.c \ > $(srcdir)/cstring.c \ > @@ -35,7 +36,8 @@ SRCS= $(srcdir)/argv_parse.c \ > $(srcdir)/quotaio.c \ > $(srcdir)/quotaio_tree.c \ > $(srcdir)/quotaio_v2.c \ > - $(srcdir)/dict.c > + $(srcdir)/dict.c \ > + $(srcdir)/json-out.c > > LIBRARY= libsupport > LIBDIR= support > @@ -165,3 +167,4 @@ quotaio_v2.o: $(srcdir)/quotaio_v2.c > $(top_builddir)/lib/config.h \ $(srcdir)/dqblk_v2.h > $(srcdir)/quotaio_tree.h dict.o: $(srcdir)/dict.c > $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h > $(srcdir)/dict.h +json-out.o: $(srcdir)/json-out.c > $(srcdir)/json-out.h diff --git a/lib/support/json-out.c > b/lib/support/json-out.c new file mode 100644 > index 00000000..8c822f35 > --- /dev/null > +++ b/lib/support/json-out.c > @@ -0,0 +1,326 @@ > +/* > + * json-out.c -- JSON output > + * > + * Copyright (c) 2018 Virtuozzo International GmbH > + * > + * %Begin-Header% > + * This file may be redistributed under the terms of the GNU Public > + * License. > + * %End-Header% > + */ > + > +#include <stdio.h> > +#include <string.h> > +#include <stdlib.h> > +#include <stdarg.h> > + > +#include "json-out.h" > + > +static void *xmalloc(size_t size) > +{ > + void *p = malloc(size); > + > + if (!p) > + exit(1); > + > + return p; > +} > + > +static void *xstrdup(const char *str) > +{ > + size_t size = strlen(str) + 1; > + char *p = xmalloc(size); > + > + return strcpy(p, str); > +} > + > +struct json_list *json_list_create(enum json_val_type type) > +{ > + struct json_list *list = xmalloc(sizeof(struct json_list)); > + > + list->node = NULL; > + list->type = type; > + > + return list; > +} > + > +struct json_list *json_list_create_in_obj(struct json_obj > *parent_obj, char *key, enum json_val_type type) +{ > + struct json_list *list = json_list_create(type); > + > + json_obj_add_list(parent_obj, key, list); > + > + return list; > +} > + > +void json_list_delete(struct json_list *list) > +{ > + struct json_list_node *node = list->node, *next; > + > + while (node) { > + switch (list->type) { > + case JSON_VAL_STRING: > + free(node->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_delete(node->val.list); > + break; > + case JSON_VAL_OBJECT: > + json_obj_delete(node->val.obj); > + break; > + default: > + break; > + } > + next = node->next; > + free(node); > + node = next; > + } > + free(list); > +} > + > +struct json_obj *json_obj_create(void) > +{ > + struct json_obj *obj = xmalloc(sizeof(struct json_obj)); > + > + obj->pair = NULL; > + > + return obj; > +} > + > +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, > char *key) +{ > + struct json_obj *obj = json_obj_create(); > + > + json_obj_add_obj(parent_obj, key, obj); > + > + return obj; > +} > + > +static void json_pair_delete(struct json_pair *pair) > +{ > + switch (pair->type) > + { > + case JSON_VAL_STRING: > + free(pair->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_delete(pair->val.list); > + break; > + case JSON_VAL_OBJECT: > + json_obj_delete(pair->val.obj); > + break; > + default: > + break; > + } > + free(pair->key); > + free(pair); > +} > + > +void json_obj_delete(struct json_obj *obj) > +{ > + struct json_pair *pair = obj->pair, *next; > + > + while (pair) { > + next = pair->next; > + json_pair_delete(pair); > + pair = next; > + } > + free(obj); > +} > + > +void json_obj_delete_pair(struct json_obj *obj, char *key) > +{ > + struct json_pair *pair = obj->pair, *next, *prev = NULL; > + > + while (pair) { > + next = pair->next; > + if (!strcmp(pair->key, key)) { > + json_pair_delete(pair); > + if (prev) > + prev->next = next; > + else > + obj->pair = next; > + break; > + } > + prev = pair; > + pair = next; > + } > +} > + > +static struct json_list_node *json_list_add_node(struct json_list > *list) +{ > + struct json_list_node *new_node = xmalloc(sizeof(struct > json_list_node)); + > + new_node->next = NULL; > + > + if (list->node) { > + struct json_list_node *node; > + > + for (node = list->node; node && node->next; node = > node->next); > + node->next = new_node; > + } else > + list->node = new_node; > + > + return new_node; > +} > + > +void json_list_add_str(struct json_list *list, const char *str) > +{ > + struct json_list_node *new_node = json_list_add_node(list); > + > + new_node->val.str = xstrdup(str); > +} > + > +void json_list_add_obj(struct json_list *list, struct json_obj *obj) > +{ > + struct json_list_node *new_node = json_list_add_node(list); > + > + new_node->val.obj = obj; > +} > + > +static struct json_pair *json_obj_add_pair(struct json_obj *obj, > const char *key, enum json_val_type type) +{ > + struct json_pair *new_pair = xmalloc(sizeof(struct > json_pair)); > + new_pair->key = xstrdup(key); > + new_pair->next = NULL; > + new_pair->type = type; > + > + if (obj->pair) { > + struct json_pair *pair; > + > + for (pair = obj->pair; pair && pair->next; pair = > pair->next); > + pair->next = new_pair; > + } else > + obj->pair = new_pair; > + > + return new_pair; > +} > + > +void json_obj_add_str(struct json_obj *obj, const char *key, const > char *str) +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, > JSON_VAL_STRING); + > + new_pair->val.str = xstrdup(str); > +} > + > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, > char *buf, size_t size, const char *fmt, ...) +{ > + va_list ap; > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > +} > + > +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, > size_t size, const char *fmt, ...) +{ > + va_list ap; > + char *buf = malloc(size); > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > + free(buf); > +} > + > +void json_obj_add_list(struct json_obj *obj, const char *key, struct > json_list *list) +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, > JSON_VAL_LIST); + > + new_pair->val.list = list; > +} > + > +void json_obj_add_obj(struct json_obj *obj, const char *key, struct > json_obj *new_obj) +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, > JSON_VAL_OBJECT); + > + new_pair->val.obj = new_obj; > +} > + > +static void json_pair_print_json(struct json_pair *pair, int > ind_lvl); +static void json_list_node_print_json(struct > json_list_node *node, enum json_val_type type, int ind_lvl); + > +static void > +print_ind(int ind_lvl) > +{ > + int i; > + > + putchar('\n'); > + for (i = 0; i < ind_lvl; i++) > + fputs(" ", stdout); > +} > + > +void json_obj_print_json(struct json_obj *obj, int ind_lvl) > +{ > + struct json_pair *pair; > + > + printf("{"); > + for (pair = obj->pair; pair; pair = pair->next) { > + json_pair_print_json(pair, ind_lvl+1); > + if (pair->next) > + printf(", "); > + } > + if (obj->pair) /* Do not indent if object was empty */ > + print_ind(ind_lvl); > + printf("}"); > +} > + > +void json_list_print_json(struct json_list *list, int ind_lvl) > +{ > + struct json_list_node *node; > + > + printf("["); > + for (node = list->node; node; node = node->next) { > + json_list_node_print_json(node, list->type, > ind_lvl+1); > + if (node->next) > + printf(", "); > + } > + if (list->node) /* Do not indent if list was empty */ > + print_ind(ind_lvl); > + printf("]"); > +} > + > +static void > +json_list_node_print_json(struct json_list_node *node, enum > json_val_type type, int ind_lvl) +{ > + print_ind(ind_lvl); > + switch (type) { > + case JSON_VAL_STRING: > + printf("\"%s\"", node->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_print_json(node->val.list, ind_lvl); > + break; > + case JSON_VAL_OBJECT: > + json_obj_print_json(node->val.obj, ind_lvl); > + break; > + case JSON_VAL_FLAG: > + printf("%s", node->val.flag ? "true" : "false"); > + break; > + default: > + break; > + } > +} > + > +static void json_pair_print_json(struct json_pair *pair, int ind_lvl) > +{ > + print_ind(ind_lvl); > + printf("\"%s\": ", pair->key); > + switch (pair->type) { > + case JSON_VAL_STRING: > + printf("\"%s\"", pair->val.str); > + break; > + case JSON_VAL_LIST: > + json_list_print_json(pair->val.list, ind_lvl); > + break; > + case JSON_VAL_OBJECT: > + json_obj_print_json(pair->val.obj, ind_lvl); > + break; > + default: > + break; > + } > +} > diff --git a/lib/support/json-out.h b/lib/support/json-out.h > new file mode 100644 > index 00000000..0132bd2c > --- /dev/null > +++ b/lib/support/json-out.h > @@ -0,0 +1,69 @@ > +/* > + * json-out.h -- JSON output > + * > + * Copyright (c) 2018 Virtuozzo International GmbH > + * > + * %Begin-Header% > + * This file may be redistributed under the terms of the GNU Public > + * License. > + * %End-Header% > + */ > + > +#ifndef H_JSON_OUT > +#define H_JSON_OUT > + > +enum json_val_type { > + JSON_VAL_STRING, > + JSON_VAL_OBJECT, > + JSON_VAL_LIST, > + JSON_VAL_FLAG > +}; > + > +struct json_obj { > + struct json_pair *pair; > +}; > + > +union json_val { > + char *str; > + struct json_obj *obj; > + struct json_list *list; > + char flag; > +}; > + > +struct json_pair { > + char *key; > + enum json_val_type type; > + union json_val val; > + struct json_pair *next; > +}; > + > +struct json_list { > + enum json_val_type type; > + struct json_list_node *node; > +}; > + > +struct json_list_node { > + union json_val val; > + struct json_list_node *next; > +}; > + > +struct json_obj *json_obj_create(void); > +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, > char *key); +void json_obj_add_str(struct json_obj *obj, const char > *key, const char *str); +void json_obj_add_list(struct json_obj *obj, > const char *key, struct json_list *list); +void > json_obj_add_obj(struct json_obj *obj, const char *key, struct > json_obj *new_obj); +void json_obj_add_flag(struct json_obj *obj, > const char *key, char flag); +void json_obj_add_fmt_str(struct > json_obj *obj, const char *key, size_t size, const char *fmt, ...); > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, > char *buf, size_t size, const char *fmt, ...); +void > json_obj_print_json(struct json_obj *obj, int ind_lvl); +void > json_obj_delete_pair(struct json_obj *obj, char *key); +void > json_obj_delete(struct json_obj *obj); + +struct json_list > *json_list_create(enum json_val_type type); +struct json_list > *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum > json_val_type type); +void json_list_add_str(struct json_list *list, > const char *str); +void json_list_add_obj(struct json_list *list, > struct json_obj *obj); +void json_list_print_json(struct json_list > *list, int ind_lvl); +void json_list_delete(struct json_list *list); > + +#endif diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c > index 395ea9ee..ca9953a1 100644 > --- a/misc/dumpe2fs.c > +++ b/misc/dumpe2fs.c > @@ -607,7 +607,12 @@ try_open_again: > goto just_descriptors; > list_super (fs->super); > if (ext2fs_has_feature_journal_dev(fs->super)) { > - print_journal_information(fs); > + print_journal_information(fs, dump_obj); > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > exit(0); > } > @@ -616,6 +621,11 @@ try_open_again: > print_inline_journal_information(fs); > list_bad_blocks(fs, 0); > if (header_only) { > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > exit (0); > } > @@ -636,6 +646,11 @@ just_descriptors: > error_message(retval)); > } > } > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > remove_error_table(&et_ext2_error_table); > exit (0);
On Feb 20, 2018, at 2:59 AM, Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> wrote: > > This patch adds JSON objects and lists and methods to print them This patch also adds the JSON routines to dumpe2fs, but in a way that is non-functional. Those changes to dumpe2fs should be moved into the 2/3 patch so that git bisect does not break if only this patch is applied. Secondly, my preference would be if the JSON functionality depended on a "configure --enable-json" check that set JSON_CMT, JSON_MAN, and ENABLE_JSON appropriately, so that this functionality could be #ifdef'd out if not needed. It is fine to have JSON formatting enabled by default, but I don't think it is needed in all environments. More comments inline. > Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> > --- > > new file mode 100644 > index 00000000..8c822f35 > --- /dev/null > +++ b/lib/support/json-out.c > @@ -0,0 +1,326 @@ > +/* > + * json-out.c -- JSON output > + * > + * Copyright (c) 2018 Virtuozzo International GmbH > + * > + * %Begin-Header% > + * This file may be redistributed under the terms of the GNU Public > + * License. > + * %End-Header% > > +static struct json_pair *json_obj_add_pair(struct json_obj *obj, const char *key, enum json_val_type type) > +{ > + struct json_pair *new_pair = xmalloc(sizeof(struct json_pair)); (style) blank line after variable declaration. > + new_pair->key = xstrdup(key); > + new_pair->next = NULL; > + new_pair->type = type; > + > + if (obj->pair) { > + struct json_pair *pair; > + > + for (pair = obj->pair; pair && pair->next; pair = pair->next); > + pair->next = new_pair; > + } else > + obj->pair = new_pair; (style) use {} in "else" block when "if" block has {} > +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str) > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_STRING); > + > + new_pair->val.str = xstrdup(str); > +} > + > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...) (style) wrap line at 80 chars > +{ > + va_list ap; > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > +} > + > +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...) (style) wrap line at 80 chars > +{ > + va_list ap; > + char *buf = malloc(size); > + > + va_start(ap, fmt); > + vsnprintf(buf, size, fmt, ap); > + va_end(ap); > + > + json_obj_add_str(obj, key, buf); > + free(buf); > +} > + > +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list) ... > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_LIST); > + > + new_pair->val.list = list; > +} > + > +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj) ... > +{ > + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_OBJECT); > + > + new_pair->val.obj = new_obj; > +} > + > +static void json_pair_print_json(struct json_pair *pair, int ind_lvl); > +static void json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl); ... > + > +static void > +print_ind(int ind_lvl) (style) "static void" should be on the same line as "print_ind()". IMHO, calling this function "print_indent()" would be more clear. I thought it was "print_index()"... > +{ > + int i; > + > + putchar('\n'); > + for (i = 0; i < ind_lvl; i++) > + fputs(" ", stdout); (style) this line should be indented > +static void > +json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl) (style) "static void" on same line as function, wrap at 80 chars > diff --git a/lib/support/json-out.h b/lib/support/json-out.h > new file mode 100644 > index 00000000..0132bd2c > --- /dev/null > +++ b/lib/support/json-out.h > @@ -0,0 +1,69 @@ > > +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list); > +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj); > +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...); > +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...); > +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type); (style) wrap lines at 80 chars > diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c > index 395ea9ee..ca9953a1 100644 > --- a/misc/dumpe2fs.c > +++ b/misc/dumpe2fs.c > @@ -607,7 +607,12 @@ try_open_again: > goto just_descriptors; > list_super (fs->super); > if (ext2fs_has_feature_journal_dev(fs->super)) { > - print_journal_information(fs); > + print_journal_information(fs, dump_obj); > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } (defect) the "json" variable is not yet declared in this patch, it is only added in patch 2/3, so all of these changes should also be moved to the 2/3 patch. > ext2fs_close_free(&fs); > exit(0); > } > @@ -616,6 +621,11 @@ try_open_again: > print_inline_journal_information(fs); > list_bad_blocks(fs, 0); > if (header_only) { > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > exit (0); > } > @@ -636,6 +646,11 @@ just_descriptors: > error_message(retval)); > } > } > + if (json) { > + json_obj_print_json(dump_obj, 0); > + putchar('\n'); > + json_obj_delete(dump_obj); > + } > ext2fs_close_free(&fs); > remove_error_table(&et_ext2_error_table); > exit (0); > -- > 2.14.1 > Cheers, Andreas
diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in index 40206b74..42fa3324 100644 --- a/lib/support/Makefile.in +++ b/lib/support/Makefile.in @@ -22,7 +22,8 @@ OBJS= cstring.o \ quotaio.o \ quotaio_v2.o \ quotaio_tree.o \ - dict.o + dict.o \ + json-out.o SRCS= $(srcdir)/argv_parse.c \ $(srcdir)/cstring.c \ @@ -35,7 +36,8 @@ SRCS= $(srcdir)/argv_parse.c \ $(srcdir)/quotaio.c \ $(srcdir)/quotaio_tree.c \ $(srcdir)/quotaio_v2.c \ - $(srcdir)/dict.c + $(srcdir)/dict.c \ + $(srcdir)/json-out.c LIBRARY= libsupport LIBDIR= support @@ -165,3 +167,4 @@ quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ $(srcdir)/dqblk_v2.h $(srcdir)/quotaio_tree.h dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h +json-out.o: $(srcdir)/json-out.c $(srcdir)/json-out.h diff --git a/lib/support/json-out.c b/lib/support/json-out.c new file mode 100644 index 00000000..8c822f35 --- /dev/null +++ b/lib/support/json-out.c @@ -0,0 +1,326 @@ +/* + * json-out.c -- JSON output + * + * Copyright (c) 2018 Virtuozzo International GmbH + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "json-out.h" + +static void *xmalloc(size_t size) +{ + void *p = malloc(size); + + if (!p) + exit(1); + + return p; +} + +static void *xstrdup(const char *str) +{ + size_t size = strlen(str) + 1; + char *p = xmalloc(size); + + return strcpy(p, str); +} + +struct json_list *json_list_create(enum json_val_type type) +{ + struct json_list *list = xmalloc(sizeof(struct json_list)); + + list->node = NULL; + list->type = type; + + return list; +} + +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type) +{ + struct json_list *list = json_list_create(type); + + json_obj_add_list(parent_obj, key, list); + + return list; +} + +void json_list_delete(struct json_list *list) +{ + struct json_list_node *node = list->node, *next; + + while (node) { + switch (list->type) { + case JSON_VAL_STRING: + free(node->val.str); + break; + case JSON_VAL_LIST: + json_list_delete(node->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_delete(node->val.obj); + break; + default: + break; + } + next = node->next; + free(node); + node = next; + } + free(list); +} + +struct json_obj *json_obj_create(void) +{ + struct json_obj *obj = xmalloc(sizeof(struct json_obj)); + + obj->pair = NULL; + + return obj; +} + +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key) +{ + struct json_obj *obj = json_obj_create(); + + json_obj_add_obj(parent_obj, key, obj); + + return obj; +} + +static void json_pair_delete(struct json_pair *pair) +{ + switch (pair->type) + { + case JSON_VAL_STRING: + free(pair->val.str); + break; + case JSON_VAL_LIST: + json_list_delete(pair->val.list); + break; + case JSON_VAL_OBJECT: + json_obj_delete(pair->val.obj); + break; + default: + break; + } + free(pair->key); + free(pair); +} + +void json_obj_delete(struct json_obj *obj) +{ + struct json_pair *pair = obj->pair, *next; + + while (pair) { + next = pair->next; + json_pair_delete(pair); + pair = next; + } + free(obj); +} + +void json_obj_delete_pair(struct json_obj *obj, char *key) +{ + struct json_pair *pair = obj->pair, *next, *prev = NULL; + + while (pair) { + next = pair->next; + if (!strcmp(pair->key, key)) { + json_pair_delete(pair); + if (prev) + prev->next = next; + else + obj->pair = next; + break; + } + prev = pair; + pair = next; + } +} + +static struct json_list_node *json_list_add_node(struct json_list *list) +{ + struct json_list_node *new_node = xmalloc(sizeof(struct json_list_node)); + + new_node->next = NULL; + + if (list->node) { + struct json_list_node *node; + + for (node = list->node; node && node->next; node = node->next); + node->next = new_node; + } else + list->node = new_node; + + return new_node; +} + +void json_list_add_str(struct json_list *list, const char *str) +{ + struct json_list_node *new_node = json_list_add_node(list); + + new_node->val.str = xstrdup(str); +} + +void json_list_add_obj(struct json_list *list, struct json_obj *obj) +{ + struct json_list_node *new_node = json_list_add_node(list); + + new_node->val.obj = obj; +} + +static struct json_pair *json_obj_add_pair(struct json_obj *obj, const char *key, enum json_val_type type) +{ + struct json_pair *new_pair = xmalloc(sizeof(struct json_pair)); + new_pair->key = xstrdup(key); + new_pair->next = NULL; + new_pair->type = type; + + if (obj->pair) { + struct json_pair *pair; + + for (pair = obj->pair; pair && pair->next; pair = pair->next); + pair->next = new_pair; + } else + obj->pair = new_pair; + + return new_pair; +} + +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_STRING); + + new_pair->val.str = xstrdup(str); +} + +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, size, fmt, ap); + va_end(ap); + + json_obj_add_str(obj, key, buf); +} + +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...) +{ + va_list ap; + char *buf = malloc(size); + + va_start(ap, fmt); + vsnprintf(buf, size, fmt, ap); + va_end(ap); + + json_obj_add_str(obj, key, buf); + free(buf); +} + +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_LIST); + + new_pair->val.list = list; +} + +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj) +{ + struct json_pair *new_pair = json_obj_add_pair(obj, key, JSON_VAL_OBJECT); + + new_pair->val.obj = new_obj; +} + +static void json_pair_print_json(struct json_pair *pair, int ind_lvl); +static void json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl); + +static void +print_ind(int ind_lvl) +{ + int i; + + putchar('\n'); + for (i = 0; i < ind_lvl; i++) + fputs(" ", stdout); +} + +void json_obj_print_json(struct json_obj *obj, int ind_lvl) +{ + struct json_pair *pair; + + printf("{"); + for (pair = obj->pair; pair; pair = pair->next) { + json_pair_print_json(pair, ind_lvl+1); + if (pair->next) + printf(", "); + } + if (obj->pair) /* Do not indent if object was empty */ + print_ind(ind_lvl); + printf("}"); +} + +void json_list_print_json(struct json_list *list, int ind_lvl) +{ + struct json_list_node *node; + + printf("["); + for (node = list->node; node; node = node->next) { + json_list_node_print_json(node, list->type, ind_lvl+1); + if (node->next) + printf(", "); + } + if (list->node) /* Do not indent if list was empty */ + print_ind(ind_lvl); + printf("]"); +} + +static void +json_list_node_print_json(struct json_list_node *node, enum json_val_type type, int ind_lvl) +{ + print_ind(ind_lvl); + switch (type) { + case JSON_VAL_STRING: + printf("\"%s\"", node->val.str); + break; + case JSON_VAL_LIST: + json_list_print_json(node->val.list, ind_lvl); + break; + case JSON_VAL_OBJECT: + json_obj_print_json(node->val.obj, ind_lvl); + break; + case JSON_VAL_FLAG: + printf("%s", node->val.flag ? "true" : "false"); + break; + default: + break; + } +} + +static void json_pair_print_json(struct json_pair *pair, int ind_lvl) +{ + print_ind(ind_lvl); + printf("\"%s\": ", pair->key); + switch (pair->type) { + case JSON_VAL_STRING: + printf("\"%s\"", pair->val.str); + break; + case JSON_VAL_LIST: + json_list_print_json(pair->val.list, ind_lvl); + break; + case JSON_VAL_OBJECT: + json_obj_print_json(pair->val.obj, ind_lvl); + break; + default: + break; + } +} diff --git a/lib/support/json-out.h b/lib/support/json-out.h new file mode 100644 index 00000000..0132bd2c --- /dev/null +++ b/lib/support/json-out.h @@ -0,0 +1,69 @@ +/* + * json-out.h -- JSON output + * + * Copyright (c) 2018 Virtuozzo International GmbH + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#ifndef H_JSON_OUT +#define H_JSON_OUT + +enum json_val_type { + JSON_VAL_STRING, + JSON_VAL_OBJECT, + JSON_VAL_LIST, + JSON_VAL_FLAG +}; + +struct json_obj { + struct json_pair *pair; +}; + +union json_val { + char *str; + struct json_obj *obj; + struct json_list *list; + char flag; +}; + +struct json_pair { + char *key; + enum json_val_type type; + union json_val val; + struct json_pair *next; +}; + +struct json_list { + enum json_val_type type; + struct json_list_node *node; +}; + +struct json_list_node { + union json_val val; + struct json_list_node *next; +}; + +struct json_obj *json_obj_create(void); +struct json_obj *json_obj_create_in_obj(struct json_obj *parent_obj, char *key); +void json_obj_add_str(struct json_obj *obj, const char *key, const char *str); +void json_obj_add_list(struct json_obj *obj, const char *key, struct json_list *list); +void json_obj_add_obj(struct json_obj *obj, const char *key, struct json_obj *new_obj); +void json_obj_add_flag(struct json_obj *obj, const char *key, char flag); +void json_obj_add_fmt_str(struct json_obj *obj, const char *key, size_t size, const char *fmt, ...); +void json_obj_add_fmt_buf_str(struct json_obj *obj, const char *key, char *buf, size_t size, const char *fmt, ...); +void json_obj_print_json(struct json_obj *obj, int ind_lvl); +void json_obj_delete_pair(struct json_obj *obj, char *key); +void json_obj_delete(struct json_obj *obj); + +struct json_list *json_list_create(enum json_val_type type); +struct json_list *json_list_create_in_obj(struct json_obj *parent_obj, char *key, enum json_val_type type); +void json_list_add_str(struct json_list *list, const char *str); +void json_list_add_obj(struct json_list *list, struct json_obj *obj); +void json_list_print_json(struct json_list *list, int ind_lvl); +void json_list_delete(struct json_list *list); + +#endif diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c index 395ea9ee..ca9953a1 100644 --- a/misc/dumpe2fs.c +++ b/misc/dumpe2fs.c @@ -607,7 +607,12 @@ try_open_again: goto just_descriptors; list_super (fs->super); if (ext2fs_has_feature_journal_dev(fs->super)) { - print_journal_information(fs); + print_journal_information(fs, dump_obj); + if (json) { + json_obj_print_json(dump_obj, 0); + putchar('\n'); + json_obj_delete(dump_obj); + } ext2fs_close_free(&fs); exit(0); } @@ -616,6 +621,11 @@ try_open_again: print_inline_journal_information(fs); list_bad_blocks(fs, 0); if (header_only) { + if (json) { + json_obj_print_json(dump_obj, 0); + putchar('\n'); + json_obj_delete(dump_obj); + } ext2fs_close_free(&fs); exit (0); } @@ -636,6 +646,11 @@ just_descriptors: error_message(retval)); } } + if (json) { + json_obj_print_json(dump_obj, 0); + putchar('\n'); + json_obj_delete(dump_obj); + } ext2fs_close_free(&fs); remove_error_table(&et_ext2_error_table); exit (0);
This patch adds JSON objects and lists and methods to print them Signed-off-by: Viktor Prutyanov <viktor.prutyanov@virtuozzo.com> --- lib/support/Makefile.in | 7 +- lib/support/json-out.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/support/json-out.h | 69 ++++++++++ misc/dumpe2fs.c | 17 ++- 4 files changed, 416 insertions(+), 3 deletions(-) create mode 100644 lib/support/json-out.c create mode 100644 lib/support/json-out.h