Merge pull request #10961 from poettering/busctl-monitor-json
busctl: support json mode also for 'busctl monitor'
This commit is contained in:
commit
1f70196644
|
@ -8,6 +8,7 @@
|
|||
#include "alloc-util.h"
|
||||
#include "bus-dump.h"
|
||||
#include "bus-internal.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-signature.h"
|
||||
#include "bus-type.h"
|
||||
#include "bus-util.h"
|
||||
|
@ -62,6 +63,9 @@ STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep);
|
|||
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
|
||||
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
|
||||
|
||||
static int json_transform_message(sd_bus_message *m, JsonVariant **ret);
|
||||
static void json_dump_with_flags(JsonVariant *v, FILE *f);
|
||||
|
||||
static int acquire_bus(bool set_monitor, sd_bus **ret) {
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
||||
int r;
|
||||
|
@ -1132,6 +1136,43 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
|
|||
return bus_message_pcap_frame(m, arg_snaplen, f);
|
||||
}
|
||||
|
||||
static int message_json(sd_bus_message *m, FILE *f) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
|
||||
char e[2];
|
||||
int r;
|
||||
|
||||
r = json_transform_message(m, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
e[0] = m->header->endian;
|
||||
e[1] = 0;
|
||||
|
||||
r = json_build(&w, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
|
||||
JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e)),
|
||||
JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(m->header->flags)),
|
||||
JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m->header->version)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->priority != 0, "priority", JSON_BUILD_INTEGER(m->priority)),
|
||||
JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
|
||||
JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", JSON_BUILD_INTEGER(m->reply_cookie)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->sender, "sender", JSON_BUILD_STRING(m->sender)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->destination, "destination", JSON_BUILD_STRING(m->destination)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->path, "path", JSON_BUILD_STRING(m->path)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->interface, "interface", JSON_BUILD_STRING(m->interface)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->member, "member", JSON_BUILD_STRING(m->member)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->monotonic != 0, "monotonic", JSON_BUILD_INTEGER(m->monotonic)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->realtime != 0, "realtime", JSON_BUILD_INTEGER(m->realtime)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->seqnum != 0, "seqnum", JSON_BUILD_INTEGER(m->seqnum)),
|
||||
JSON_BUILD_PAIR_CONDITION(m->error.name, "error_name", JSON_BUILD_STRING(m->error.name)),
|
||||
JSON_BUILD_PAIR("payload", JSON_BUILD_VARIANT(v))));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||
|
||||
json_dump_with_flags(w, f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
|
||||
|
@ -1251,7 +1292,7 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f
|
|||
}
|
||||
|
||||
static int verb_monitor(int argc, char **argv, void *userdata) {
|
||||
return monitor(argc, argv, message_dump);
|
||||
return monitor(argc, argv, arg_json != JSON_OFF ? message_json : message_dump);
|
||||
}
|
||||
|
||||
static int verb_capture(int argc, char **argv, void *userdata) {
|
||||
|
@ -2038,7 +2079,7 @@ static int get_property(int argc, char **argv, void *userdata) {
|
|||
|
||||
json_dump_with_flags(v, stdout);
|
||||
|
||||
} else if (arg_verbose) {
|
||||
} else if (arg_verbose) {
|
||||
(void) pager_open(arg_pager_flags);
|
||||
|
||||
r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
|
||||
|
|
|
@ -2249,6 +2249,7 @@ typedef struct JsonStack {
|
|||
size_t n_elements, n_elements_allocated;
|
||||
unsigned line_before;
|
||||
unsigned column_before;
|
||||
size_t n_suppress; /* When building: if > 0, suppress this many subsequent elements. If == (size_t) -1, suppress all subsequent elements */
|
||||
} JsonStack;
|
||||
|
||||
static void json_stack_release(JsonStack *s) {
|
||||
|
@ -2656,6 +2657,8 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
for (;;) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *add = NULL;
|
||||
size_t n_subtract = 0; /* how much to subtract from current->n_suppress, i.e. how many elements would
|
||||
* have been added to the current variant */
|
||||
JsonStack *current;
|
||||
int command;
|
||||
|
||||
|
@ -2679,9 +2682,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
p = va_arg(ap, const char *);
|
||||
|
||||
r = json_variant_new_string(&add, p);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_string(&add, p);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2703,9 +2710,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
j = va_arg(ap, intmax_t);
|
||||
|
||||
r = json_variant_new_integer(&add, j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_integer(&add, j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2727,9 +2738,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
j = va_arg(ap, uintmax_t);
|
||||
|
||||
r = json_variant_new_unsigned(&add, j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_unsigned(&add, j);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2751,9 +2766,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
d = va_arg(ap, long double);
|
||||
|
||||
r = json_variant_new_real(&add, d);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_real(&add, d);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2775,9 +2794,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
b = va_arg(ap, int);
|
||||
|
||||
r = json_variant_new_boolean(&add, b);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_boolean(&add, b);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2796,9 +2819,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
r = json_variant_new_null(&add);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_null(&add);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2816,12 +2843,16 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
/* Note that we don't care for current->n_suppress here, after all the variant is already
|
||||
* allocated anyway... */
|
||||
add = va_arg(ap, JsonVariant*);
|
||||
if (!add)
|
||||
add = JSON_VARIANT_MAGIC_NULL;
|
||||
else
|
||||
json_variant_ref(add);
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
else if (current->expect == EXPECT_OBJECT_VALUE)
|
||||
|
@ -2841,13 +2872,17 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
l = va_arg(ap, const char *);
|
||||
|
||||
if (!l)
|
||||
add = JSON_VARIANT_MAGIC_NULL;
|
||||
else {
|
||||
if (l) {
|
||||
/* Note that we don't care for current->n_suppress here, we should generate parsing
|
||||
* errors even in suppressed object properties */
|
||||
|
||||
r = json_parse(l, &add, NULL, NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
} else
|
||||
add = JSON_VARIANT_MAGIC_NULL;
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2881,6 +2916,10 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
stack[n_stack++] = (JsonStack) {
|
||||
.expect = EXPECT_ARRAY_ELEMENT,
|
||||
.n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the
|
||||
* new array, then we should
|
||||
* also suppress all array
|
||||
* members */
|
||||
};
|
||||
|
||||
break;
|
||||
|
@ -2893,9 +2932,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
assert(n_stack > 1);
|
||||
|
||||
r = json_variant_new_array(&add, current->elements, current->n_elements);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_array(&add, current->elements, current->n_elements);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
json_stack_release(current);
|
||||
n_stack--, current--;
|
||||
|
@ -2912,9 +2955,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
l = va_arg(ap, char **);
|
||||
|
||||
r = json_variant_new_array_strv(&add, l);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_array_strv(&add, l);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
if (current->expect == EXPECT_TOPLEVEL)
|
||||
current->expect = EXPECT_END;
|
||||
|
@ -2948,6 +2995,10 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
stack[n_stack++] = (JsonStack) {
|
||||
.expect = EXPECT_OBJECT_KEY,
|
||||
.n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the
|
||||
* new object, then we should
|
||||
* also suppress all object
|
||||
* members */
|
||||
};
|
||||
|
||||
break;
|
||||
|
@ -2961,9 +3012,13 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
assert(n_stack > 1);
|
||||
|
||||
r = json_variant_new_object(&add, current->elements, current->n_elements);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_object(&add, current->elements, current->n_elements);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
json_stack_release(current);
|
||||
n_stack--, current--;
|
||||
|
@ -2980,15 +3035,47 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
n = va_arg(ap, const char *);
|
||||
|
||||
r = json_variant_new_string(&add, n);
|
||||
if (r < 0)
|
||||
if (current->n_suppress == 0) {
|
||||
r = json_variant_new_string(&add, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1;
|
||||
|
||||
current->expect = EXPECT_OBJECT_VALUE;
|
||||
break;
|
||||
}
|
||||
|
||||
case _JSON_BUILD_PAIR_CONDITION: {
|
||||
const char *n;
|
||||
bool b;
|
||||
|
||||
if (current->expect != EXPECT_OBJECT_KEY) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
b = va_arg(ap, int);
|
||||
n = va_arg(ap, const char *);
|
||||
|
||||
if (b && current->n_suppress == 0) {
|
||||
r = json_variant_new_string(&add, n);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
n_subtract = 1; /* we generated one item */
|
||||
|
||||
if (!b && current->n_suppress != (size_t) -1)
|
||||
current->n_suppress += 2; /* Suppress this one and the next item */
|
||||
|
||||
current->expect = EXPECT_OBJECT_VALUE;
|
||||
break;
|
||||
}}
|
||||
|
||||
if (add) {
|
||||
/* If a variant was generated, add it to our current variant, but only if we are not supposed to suppress additions */
|
||||
if (add && current->n_suppress == 0) {
|
||||
if (!GREEDY_REALLOC(current->elements, current->n_elements_allocated, current->n_elements + 1)) {
|
||||
r = -ENOMEM;
|
||||
goto finish;
|
||||
|
@ -2996,6 +3083,16 @@ int json_buildv(JsonVariant **ret, va_list ap) {
|
|||
|
||||
current->elements[current->n_elements++] = TAKE_PTR(add);
|
||||
}
|
||||
|
||||
/* If we are supposed to suppress items, let's subtract how many items where generated from that
|
||||
* counter. Except if the counter is (size_t) -1, i.e. we shall suppress an infinite number of elements
|
||||
* on this stack level */
|
||||
if (current->n_suppress != (size_t) -1) {
|
||||
if (current->n_suppress <= n_subtract) /* Saturated */
|
||||
current->n_suppress = 0;
|
||||
else
|
||||
current->n_suppress -= n_subtract;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
|
@ -177,6 +177,7 @@ enum {
|
|||
_JSON_BUILD_OBJECT_BEGIN,
|
||||
_JSON_BUILD_OBJECT_END,
|
||||
_JSON_BUILD_PAIR,
|
||||
_JSON_BUILD_PAIR_CONDITION,
|
||||
_JSON_BUILD_NULL,
|
||||
_JSON_BUILD_VARIANT,
|
||||
_JSON_BUILD_LITERAL,
|
||||
|
@ -192,6 +193,7 @@ enum {
|
|||
#define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
|
||||
#define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
|
||||
#define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
|
||||
#define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
|
||||
#define JSON_BUILD_NULL _JSON_BUILD_NULL
|
||||
#define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
|
||||
#define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
|
||||
|
|
|
@ -316,6 +316,22 @@ static void test_build(void) {
|
|||
|
||||
a = json_variant_unref(a);
|
||||
b = json_variant_unref(b);
|
||||
|
||||
assert_se(json_build(&a, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
|
||||
JSON_BUILD_PAIR("z", JSON_BUILD_STRING("a")),
|
||||
JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
|
||||
)) >= 0);
|
||||
|
||||
assert_se(json_build(&b, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("x", JSON_BUILD_STRING("y")),
|
||||
JSON_BUILD_PAIR_CONDITION(false, "p", JSON_BUILD_STRING("q")),
|
||||
JSON_BUILD_PAIR_CONDITION(true, "z", JSON_BUILD_STRING("a")),
|
||||
JSON_BUILD_PAIR_CONDITION(false, "j", JSON_BUILD_ARRAY(JSON_BUILD_STRING("k"), JSON_BUILD_STRING("u"), JSON_BUILD_STRING("i"))),
|
||||
JSON_BUILD_PAIR("b", JSON_BUILD_STRING("c"))
|
||||
)) >= 0);
|
||||
|
||||
assert_se(json_variant_equal(a, b));
|
||||
}
|
||||
|
||||
static void test_source(void) {
|
||||
|
|
Loading…
Reference in a new issue