Files
systemd/src/network/networkctl-description.c
T
Zbigniew Jędrzejewski-Szmek 23441a3d88 sd-json,tree-wide: add sd_json_format_enabled() and use it everwhere
We often used a pattern like if (!FLAGS_SET(flags, SD_JSON_FORMAT_OFF)),
which is rather verbose and also contains a double negative, which we try
to avoid. Add a little helper to avoid an explicit bit check.

This change clarifies an aditional thing: in some cases we treated
SD_JSON_FORMAT_OFF as a flag (flags & SD_JSON_FORMAT_OFF), while in other cases
we treated it as an independent enum value (flags == SD_JSON_FORMAT_OFF).
In the first form, flags like SD_JSON_FORMAT_SSE do _not_ turn the json
output on, while in the second form they do. Let's use the first form
everywhere.

No functional change intended.

Initially I wasn't sure if this helper should be made public or just internal,
but it seems such a common pattern that if we expose the flags, we might just
as well expose it too, to make life easier for any consumers.
2024-10-28 09:23:07 +01:00

141 lines
4.5 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-util.h"
#include "glob-util.h"
#include "json-util.h"
#include "networkctl.h"
#include "networkctl-description.h"
#include "networkctl-util.h"
#include "stdio-util.h"
#include "strv.h"
static int get_description(sd_bus *bus, sd_json_variant **ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *text;
int r;
assert(bus);
assert(ret);
r = bus_call_method(bus, bus_network_mgr, "Describe", &error, &reply, NULL);
if (r < 0)
return log_error_errno(r, "Failed to get description: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &text);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_parse(text, 0, ret, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to parse JSON: %m");
return 0;
}
static int dump_manager_description(sd_bus *bus) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int r;
assert(bus);
r = get_description(bus, &v);
if (r < 0)
return r;
sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
return 0;
}
static int dump_link_description(sd_bus *bus, char * const *patterns) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_free_ bool *matched_patterns = NULL;
sd_json_variant *i;
size_t c = 0;
int r;
assert(bus);
assert(patterns);
r = get_description(bus, &v);
if (r < 0)
return r;
matched_patterns = new0(bool, strv_length(patterns));
if (!matched_patterns)
return log_oom();
JSON_VARIANT_ARRAY_FOREACH(i, sd_json_variant_by_key(v, "Interfaces")) {
char ifindex_str[DECIMAL_STR_MAX(int64_t)];
const char *name;
int64_t index;
size_t pos;
name = sd_json_variant_string(sd_json_variant_by_key(i, "Name"));
index = sd_json_variant_integer(sd_json_variant_by_key(i, "Index"));
xsprintf(ifindex_str, "%" PRIi64, index);
if (!strv_fnmatch_full(patterns, ifindex_str, 0, &pos) &&
!strv_fnmatch_full(patterns, name, 0, &pos)) {
bool match = false;
sd_json_variant *a;
JSON_VARIANT_ARRAY_FOREACH(a, sd_json_variant_by_key(i, "AlternativeNames"))
if (strv_fnmatch_full(patterns, sd_json_variant_string(a), 0, &pos)) {
match = true;
break;
}
if (!match)
continue;
}
matched_patterns[pos] = true;
sd_json_variant_dump(i, arg_json_format_flags, NULL, NULL);
c++;
}
/* Look if we matched all our arguments that are not globs. It is OK for a glob to match
* nothing, but not for an exact argument. */
for (size_t pos = 0; pos < strv_length(patterns); pos++) {
if (matched_patterns[pos])
continue;
if (string_is_glob(patterns[pos]))
log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
patterns[pos]);
else
return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
"Interface \"%s\" not found.", patterns[pos]);
}
if (c == 0)
log_warning("No interfaces matched.");
return 0;
}
int dump_description(int argc, char *argv[]) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (!sd_json_format_enabled(arg_json_format_flags))
return 0;
r = acquire_bus(&bus);
if (r < 0)
return r;
if (arg_all || argc <= 1)
r = dump_manager_description(bus);
else
r = dump_link_description(bus, strv_skip(argv, 1));
if (r < 0)
return r;
return 1; /* done */
}