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.
141 lines
4.5 KiB
C
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 */
|
|
}
|