-/* $OpenBSD: json.c,v 1.8 2023/05/05 07:42:40 claudio Exp $ */
+/* $OpenBSD: json.c,v 1.9 2023/06/05 16:24:05 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
static struct json_stack {
const char *name;
unsigned int count;
+ int compact;
enum json_type type;
} stack[JSON_MAX_STACK];
static void
do_comma_indent(void)
{
- if (stack[level].count++ > 0)
+ char sp = '\n';
+
+ if (stack[level].compact)
+ sp = ' ';
+
+ if (stack[level].count++ > 0) {
if (!eb)
- eb = fprintf(jsonfh, ",\n") < 0;
+ eb = fprintf(jsonfh, ",%c", sp) < 0;
+ }
+
+ if (stack[level].compact)
+ return;
if (!eb)
eb = fprintf(jsonfh, "\t%.*s", level, indent) < 0;
}
json_do_array(const char *name)
{
int i, l;
+ char sp = '\n';
if ((l = do_find(ARRAY, name)) > 0) {
/* array already in use, close element and move on */
if (stack[level].type == ARRAY)
json_do_end();
+ if (stack[level].compact)
+ sp = ' ';
do_comma_indent();
do_name(name);
if (!eb)
- eb = fprintf(jsonfh, "[\n") < 0;
+ eb = fprintf(jsonfh, "[%c", sp) < 0;
if (++level >= JSON_MAX_STACK)
errx(1, "json stack too deep");
stack[level].name = name;
stack[level].type = ARRAY;
stack[level].count = 0;
+ /* inherit compact setting from above level */
+ stack[level].compact = stack[level - 1].compact;
}
void
-json_do_object(const char *name)
+json_do_object(const char *name, int compact)
{
int i, l;
+ char sp = '\n';
if ((l = do_find(OBJECT, name)) > 0) {
/* roll back to that object and close it */
json_do_end();
}
+ if (compact)
+ sp = ' ';
do_comma_indent();
do_name(name);
if (!eb)
- eb = fprintf(jsonfh, "{\n") < 0;
+ eb = fprintf(jsonfh, "{%c", sp) < 0;
if (++level >= JSON_MAX_STACK)
errx(1, "json stack too deep");
stack[level].name = name;
stack[level].type = OBJECT;
stack[level].count = 0;
+ stack[level].compact = compact;
}
void
json_do_end(void)
{
- if (stack[level].type == ARRAY) {
- if (!eb)
- eb = fprintf(jsonfh, "\n%.*s]", level, indent) < 0;
- } else if (stack[level].type == OBJECT) {
+ char c;
+
+ if (stack[level].type == ARRAY)
+ c = ']';
+ else if (stack[level].type == OBJECT)
+ c = '}';
+ else
+ errx(1, "json bad stack state");
+
+ if (!stack[level].compact) {
if (!eb)
- eb = fprintf(jsonfh, "\n%.*s}", level, indent) < 0;
+ eb = fprintf(jsonfh, "\n%.*s%c", level, indent, c) < 0;
} else {
- errx(1, "json bad stack state");
+ if (!eb)
+ eb = fprintf(jsonfh, " %c", c) < 0;
}
+
stack[level].name = NULL;
stack[level].type = NONE;
stack[level].count = 0;
+ stack[level].compact = 0;
if (level-- <= 0)
errx(1, "json stack underflow");
-/* $OpenBSD: output_json.c,v 1.34 2023/05/05 07:42:40 claudio Exp $ */
+/* $OpenBSD: output_json.c,v 1.35 2023/06/05 16:24:05 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
!capa->refresh && !capa->enhanced_rr && !capa->as4byte)
return;
- json_do_object("capabilities");
+ json_do_object("capabilities", 0);
json_do_bool("as4byte", capa->as4byte);
json_do_bool("refresh", capa->refresh);
json_do_bool("enhanced_refresh", capa->enhanced_rr);
restarted = 1;
break;
}
- json_do_object("graceful_restart");
+ json_do_object("graceful_restart", 0);
json_do_bool("eor", 1);
json_do_bool("restart", restarted);
json_do_array("protocols");
for (i = AID_MIN; i < AID_MAX; i++)
if (capa->grestart.flags[i] & CAPA_GR_PRESENT) {
- json_do_object("family");
+ json_do_object("family", 1);
json_do_string("family", aid2str(i));
json_do_bool("preserved",
capa->grestart.flags[i] &
json_do_array("add-path");
for (i = AID_MIN; i < AID_MAX; i++)
if (capa->add_path[i]) {
- json_do_object("add-path-elm");
+ json_do_object("add-path-elm", 1);
json_do_string("family", aid2str(i));
switch (capa->add_path[i]) {
case CAPA_AP_RECV:
static void
json_neighbor_stats(struct peer *p)
{
- json_do_object("stats");
+ json_do_object("stats", 0);
json_do_string("last_read", fmt_monotime(p->stats.last_read));
json_do_int("last_read_sec", get_monotime(p->stats.last_read));
json_do_string("last_write", fmt_monotime(p->stats.last_write));
json_do_int("last_write_sec", get_monotime(p->stats.last_write));
- json_do_object("prefixes");
+ json_do_object("prefixes", 1);
json_do_uint("sent", p->stats.prefix_out_cnt);
json_do_uint("received", p->stats.prefix_cnt);
json_do_end();
- json_do_object("message");
+ json_do_object("message", 0);
- json_do_object("sent");
+ json_do_object("sent", 0);
json_do_uint("open", p->stats.msg_sent_open);
json_do_uint("notifications", p->stats.msg_sent_notification);
json_do_uint("updates", p->stats.msg_sent_update);
p->stats.msg_sent_rrefresh);
json_do_end();
- json_do_object("received");
+ json_do_object("received", 0);
json_do_uint("open", p->stats.msg_rcvd_open);
json_do_uint("notifications", p->stats.msg_rcvd_notification);
json_do_uint("updates", p->stats.msg_rcvd_update);
json_do_end();
- json_do_object("update");
+ json_do_object("update", 0);
- json_do_object("sent");
+ json_do_object("sent", 1);
json_do_uint("updates", p->stats.prefix_sent_update);
json_do_uint("withdraws", p->stats.prefix_sent_withdraw);
json_do_uint("eor", p->stats.prefix_sent_eor);
json_do_end();
- json_do_object("received");
+ json_do_object("received", 1);
json_do_uint("updates", p->stats.prefix_rcvd_update);
json_do_uint("withdraws", p->stats.prefix_rcvd_withdraw);
json_do_uint("eor", p->stats.prefix_rcvd_eor);
json_do_end();
- json_do_object("pending");
+ json_do_object("pending", 1);
json_do_uint("updates", p->stats.pending_update);
json_do_uint("withdraws", p->stats.pending_withdraw);
json_do_end();
json_do_end();
- json_do_object("route-refresh");
+ json_do_object("route-refresh", 0);
- json_do_object("sent");
+ json_do_object("sent", 1);
json_do_uint("request", p->stats.refresh_sent_req);
json_do_uint("borr", p->stats.refresh_sent_borr);
json_do_uint("eorr", p->stats.refresh_sent_eorr);
json_do_end();
- json_do_object("received");
+ json_do_object("received", 1);
json_do_uint("request", p->stats.refresh_rcvd_req);
json_do_uint("borr", p->stats.refresh_rcvd_borr);
json_do_uint("eorr", p->stats.refresh_rcvd_eorr);
const char *errstr;
/* config */
- json_do_object("config");
+ json_do_object("config", 0);
json_do_bool("template", p->conf.template);
json_do_bool("cloned", p->template != NULL);
json_do_bool("passive", p->conf.passive);
/* connection info */
if (p->state >= STATE_OPENSENT) {
- json_do_object("session");
+ json_do_object("session", 0);
json_do_uint("holdtime", p->holdtime);
json_do_uint("keepalive", p->holdtime / 3);
- json_do_object("local");
+ json_do_object("local", 0);
json_do_string("address", log_addr(&p->local));
json_do_uint("port", p->local_port);
json_neighbor_capabilities(&p->capa.ann);
json_do_end();
- json_do_object("remote");
+ json_do_object("remote", 0);
json_do_string("address", log_addr(&p->remote));
json_do_uint("port", p->remote_port);
json_neighbor_capabilities(&p->capa.peer);
{
json_do_array("neighbors");
- json_do_object("neighbor");
+ json_do_object("neighbor", 0);
json_do_string("remote_as", log_as(p->conf.remote_as));
if (p->conf.descr[0])
{
json_do_array("timers");
- json_do_object("timer");
+ json_do_object("timer", 1);
json_do_string("name", timernames[t->type]);
json_do_int("due", t->val);
json_do_end();
json_do_array("fib");
- json_do_object("fib_entry");
+ json_do_object("fib_entry", 0);
json_do_printf("prefix", "%s/%u", log_addr(&kf->prefix), kf->prefixlen);
json_do_uint("priority", kf->priority);
{
json_do_array("fibtables");
- json_do_object("fibtable");
+ json_do_object("fibtable", 0);
json_do_uint("rtableid", kt->rtableid);
json_do_string("description", kt->descr);
json_do_bool("coupled", kt->fib_sync);
static void
json_do_interface(struct ctl_show_interface *iface)
{
- json_do_object("interface");
+ json_do_object("interface", 0);
json_do_string("name", iface->ifname);
json_do_uint("rdomain", iface->rdomain);
{
json_do_array("nexthops");
- json_do_object("nexthop");
+ json_do_object("nexthop", 0);
json_do_string("address", log_addr(&nh->addr));
json_do_bool("valid", nh->valid);
json_do_array("attributes");
- json_do_object("attribute");
+ json_do_object("attribute", 0);
json_do_string("type", fmt_attr(type, -1));
json_do_uint("length", alen);
- json_do_object("flags");
+ json_do_object("flags", 1);
json_do_bool("partial", flags & ATTR_PARTIAL);
json_do_bool("transitive", flags & ATTR_TRANSITIVE);
json_do_bool("optional", flags & ATTR_OPTIONAL);
json_do_array("NLRI");
while (alen > 0) {
- json_do_object("prefix");
+ json_do_object("prefix", 1);
if (addpath) {
if (alen <= sizeof(pathid)) {
json_do_string("error", "bad path-id");
json_do_array("rib");
- json_do_object("rib_entry");
+ json_do_object("rib_entry", 0);
json_do_printf("prefix", "%s/%u", log_addr(&r->prefix), r->prefixlen);
json_do_string("exit_nexthop", log_addr(&r->exit_nexthop));
json_do_string("true_nexthop", log_addr(&r->true_nexthop));
- json_do_object("neighbor");
+ json_do_object("neighbor", 1);
if (r->descr[0])
json_do_string("description", r->descr);
json_do_string("remote_addr", log_addr(&r->remote_addr));
json_rib_mem_element(const char *name, uint64_t count, uint64_t size,
uint64_t refs)
{
- json_do_object(name);
+ json_do_object(name, 1);
if (count != UINT64_MAX)
json_do_uint("count", count);
if (size != UINT64_MAX)
size_t pts = 0;
int i;
- json_do_object("memory");
+ json_do_object("memory", 0);
for (i = 0; i < AID_MAX; i++) {
if (stats->pt_cnt[i] == 0)
continue;
stats->attr_data, UINT64_MAX);
json_do_end();
- json_do_object("sets");
+ json_do_object("sets", 0);
json_rib_mem_element("as_set", stats->aset_nmemb,
stats->aset_size, UINT64_MAX);
json_rib_mem_element("as_set_tables", stats->aset_cnt, UINT64_MAX,
{
json_do_array("sets");
- json_do_object("set");
+ json_do_object("set", 0);
json_do_string("name", set->name);
json_do_string("type", fmt_set_type(set));
json_do_string("last_change", fmt_monotime(set->lastchange));
{
json_do_array("rtrs");
- json_do_object("rtr");
+ json_do_object("rtr", 0);
if (rtr->descr[0])
json_do_string("descr", rtr->descr);
json_do_string("remote_addr", log_addr(&rtr->remote_addr));