1
0
mirror of https://github.com/systemd/systemd synced 2026-04-07 07:34:50 +02:00

Compare commits

...

13 Commits

Author SHA1 Message Date
Yu Watanabe
7547c3e06a
core/exec-invoke: pass the correct pid (1) to processes in pidns (#39575) 2025-11-08 02:41:14 +09:00
Yu Watanabe
88f6611260
tar-util: make sure we can unpack hardlinked symlinks (#39619) 2025-11-08 00:08:44 +09:00
Anton Tiurin
dd2934d44e network: expose Describe Varlink, use for networkctl list & status
Both `list` and `status` with `--json=pretty|short` show the description.
It is fetched via D-Bus by org.freedesktop.network1.Manager.Describe

This change exposes the same data via Varlink API `io.systemd.Network.Describe`
and migrates networkctl list and status commands to use Varlink API.

Update GetStates IDL to use enums for link states.
2025-11-08 00:08:00 +09:00
Zbigniew Jędrzejewski-Szmek
7240ec54ea
Fixes for the OSC prompt script (#39588) 2025-11-07 14:53:13 +01:00
Zbigniew Jędrzejewski-Szmek
705e2ef194 profile/osc-context: move and extend check for TERM=dumb
Let's do the check early and skip most of the file if appropriate. Also, treat
missing $TERM same as "dumb". We're almost certainly at a dump terminal in that
case.
2025-11-07 14:47:49 +01:00
Francesco Valla
840549989f modules-load: implement parallel module loading
Load modules in parallel using a pool of worker threads. The number of
threads is equal to the number of CPUs, with a maximum of 16 (to avoid
too many threads being started during boot on systems with many an high
core count, since the number of modules loaded on boot is usually on
the small side).

The number of threads can optionally be specified manually using the
SYSTEMD_MODULES_LOAD_NUM_THREADS environment variable; in this case,
no limit is enforced. If SYSTEMD_MODULES_LOAD_NUM_THREADS is set to 0,
probing happens sequentially.

Co-authored-by: Eric Curtin <ecurtin@redhat.com>
2025-11-07 14:12:56 +01:00
jouyouyun
df79e5b97e pcrextend: fix wrong format in log
`name` is string type, should use `%s` replace `%u`
2025-11-07 14:08:35 +01:00
Lennart Poettering
36e10dc5a5 tar-util: make sure we can unpack hardlinked symlinks
This is something ostree does. Yuck. But let's make t work.
2025-11-07 14:04:36 +01:00
Lennart Poettering
0ab316ff14 chase: fix typo in log message
(While we are at it, add quotes around user provided strings)
2025-11-07 14:04:19 +01:00
Zbigniew Jędrzejewski-Szmek
dd20ba74e3 profile/systemd-osc-context: fix overriding of PROMPT_COMMAND
In https://github.com/systemd/systemd/issues/39114 users are reporting
that our script overrides PROMPT_COMMAND that they had. After looking
at /etc/bashrc in Fedora, I see that it only sets PROMPT_COMMAND if
[ -z "$PROMPT_COMMAND" ]. Let's adjust the script so this continues to
work.

Fixes https://github.com/systemd/systemd/issues/39114.
(This is a bit of a stretch. 39114 was originally about SecureCRT,
but that was resolved in SecureCRT. But there was a lot of dicussion
about the prompt being overriden, which this commit should fix.)
2025-11-06 12:21:27 +01:00
Mike Yuan
96d4750e7e
core/exec-invoke: pass the correct pid (1) to processes in pidns 2025-11-05 17:47:42 +01:00
Mike Yuan
675a4841cc
core/service: do not pass $MANAGERPID and friends if pidns is employed 2025-11-05 17:28:44 +01:00
Mike Yuan
dfb4b39d4d
core/socket: fix alignment, extract common conditions 2025-11-05 17:28:25 +01:00
17 changed files with 1068 additions and 151 deletions

View File

@ -839,3 +839,10 @@ Tools using the Varlink protocol (such as `varlinkctl`) or sd-bus (such as
* `$SYSTEMD_ETC_VCONSOLE_CONF` - override the path to the virtual console
configuration file. The default is `/etc/vconsole.conf`.
`systemd-modules-load`:
* `$SYSTEMD_MODULES_LOAD_NUM_THREADS` - takes a number, which controls the
overall number of threads used to load modules by `systemd-modules-load`.
If unset, the default number of threads is equal to the number of online CPUs,
with a maximum of 16. If set to `0`, multi-threaded loading is disabled.

View File

@ -13,6 +13,10 @@
# Not bash?
[ -n "${BASH_VERSION:-}" ] || return 0
# If we're on a "dumb" terminal, do not install the prompt.
# Treat missing $TERM same as "dumb".
[ "${TERM:-dumb}" = "dumb" ] && return 0
__systemd_osc_context_escape() {
# Escape according to the OSC 3008 spec. Since this requires shelling out
# to 'sed' we'll only do it where it's strictly necessary, and skip it when
@ -56,8 +60,12 @@ __systemd_osc_context_precmdline() {
read -r systemd_osc_context_cmd_id </proc/sys/kernel/random/uuid
}
if [[ -n "${BASH_VERSION:-}" ]] && [[ "${TERM:-}" != "dumb" ]]; then
# Whenever a new prompt is shown close the previous command, and prepare new command
if [ -n "${BASH_VERSION:-}" ]; then
# Legacy bashrc will assign PROMPT_COMMAND=, which is equivalent to assigning
# index 0 in the array. Leave an empty spot to handle this gracefully.
[ -n "$(declare -p PROMPT_COMMAND 2>/dev/null)" ] || PROMPT_COMMAND+=('')
# Whenever a new prompt is shown, close the previous command, and prepare new command
PROMPT_COMMAND+=(__systemd_osc_context_precmdline)
# PS0 is shown right after a prompt completed, but before the command is executed

View File

@ -68,7 +68,7 @@ static int log_autofs_mount_point(int fd, const char *path, ChaseFlags flags) {
(void) fd_get_path(fd, &n1);
return log_warning_errno(SYNTHETIC_ERRNO(EREMOTE),
"Detected autofs mount point %s during canonicalization of %s.",
"Detected autofs mount point '%s' during canonicalization of '%s'.",
strna(n1), path);
}
@ -83,7 +83,7 @@ static int log_prohibited_symlink(int fd, ChaseFlags flags) {
(void) fd_get_path(fd, &n1);
return log_warning_errno(SYNTHETIC_ERRNO(EREMCHG),
"Detected symlink where not symlink is allowed at %s, refusing.",
"Detected symlink where no symlink is allowed at '%s', refusing.",
strna(n1));
}

View File

@ -2009,6 +2009,7 @@ static int build_environment(
_cleanup_strv_free_ char **e = NULL;
size_t n = 0;
pid_t exec_pid;
int r;
assert(c);
@ -2016,10 +2017,12 @@ static int build_environment(
assert(cgroup_context);
assert(ret);
exec_pid = needs_sandboxing && exec_needs_pid_namespace(c, p) ? 1 : getpid_cached();
if (p->n_socket_fds + p->n_stashed_fds > 0) {
_cleanup_free_ char *joined = NULL;
r = strv_extendf_with_size(&e, &n, "LISTEN_PID="PID_FMT, getpid_cached());
r = strv_extendf_with_size(&e, &n, "LISTEN_PID="PID_FMT, exec_pid);
if (r < 0)
return r;
@ -2044,7 +2047,7 @@ static int build_environment(
}
if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
r = strv_extendf_with_size(&e, &n, "WATCHDOG_PID="PID_FMT, getpid_cached());
r = strv_extendf_with_size(&e, &n, "WATCHDOG_PID="PID_FMT, exec_pid);
if (r < 0)
return r;
@ -2174,7 +2177,7 @@ static int build_environment(
return r;
}
r = strv_extendf_with_size(&e, &n, "SYSTEMD_EXEC_PID=" PID_FMT, getpid_cached());
r = strv_extendf_with_size(&e, &n, "SYSTEMD_EXEC_PID=" PID_FMT, exec_pid);
if (r < 0)
return r;

View File

@ -1810,7 +1810,9 @@ static int service_spawn_internal(
return -ENOMEM;
}
if (MANAGER_IS_USER(UNIT(s)->manager)) {
if (MANAGER_IS_USER(UNIT(s)->manager) &&
!exec_needs_pid_namespace(&s->exec_context, /* params = */ NULL)) {
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid_cached()) < 0)
return -ENOMEM;

View File

@ -1580,9 +1580,8 @@ static int socket_address_listen_in_cgroup(
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to acquire runtime: %m");
if (s->exec_runtime && s->exec_runtime->shared) {
if (s->exec_context.user_namespace_path &&
s->exec_runtime &&
s->exec_runtime->shared &&
s->exec_runtime->shared->userns_storage_socket[0] >= 0) {
r = open_shareable_ns_path(s->exec_runtime->shared->userns_storage_socket, s->exec_context.user_namespace_path, CLONE_NEWUSER);
if (r < 0)
@ -1590,8 +1589,6 @@ static int socket_address_listen_in_cgroup(
}
if (s->exec_context.network_namespace_path &&
s->exec_runtime &&
s->exec_runtime->shared &&
s->exec_runtime->shared->netns_storage_socket[0] >= 0) {
r = open_shareable_ns_path(s->exec_runtime->shared->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
if (r < 0)
@ -1599,13 +1596,12 @@ static int socket_address_listen_in_cgroup(
}
if (s->exec_context.ipc_namespace_path &&
s->exec_runtime &&
s->exec_runtime->shared &&
s->exec_runtime->shared->ipcns_storage_socket[0] >= 0) {
r = open_shareable_ns_path(s->exec_runtime->shared->ipcns_storage_socket, s->exec_context.ipc_namespace_path, CLONE_NEWIPC);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path);
}
}
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");

View File

@ -1,9 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <sys/stat.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include "alloc-util.h"
#include "assert.h"
#include "build.h"
#include "conf-files.h"
#include "constants.h"
@ -11,18 +16,61 @@
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "main-func.h"
#include "module-util.h"
#include "ordered-set.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "string-util.h"
#include "strv.h"
#define MODULE_NAME_MAX_LEN (4096UL)
static char **arg_proc_cmdline_modules = NULL;
static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d");
STATIC_DESTRUCTOR_REGISTER(arg_proc_cmdline_modules, strv_freep);
static int modules_list_append_suffix(OrderedSet **module_set, char *modp) {
/* take possession of string no matter what */
_cleanup_free_ char *mod = modp;
int r;
assert(module_set);
assert(mod);
if (strlen(mod) > MODULE_NAME_MAX_LEN)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Module name max length exceeded (%lu): %s",
MODULE_NAME_MAX_LEN, mod);
/* kmod will do it anyway later, so replace now dashes with
underscores to detect duplications due to different spelling. */
string_replace_char(mod, '-', '_');
r = ordered_set_ensure_put(module_set, &string_hash_ops_free, mod);
if (r == -EEXIST)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to enqueue module '%s': %m", mod);
TAKE_PTR(mod);
return 0;
}
static int modules_list_append_dup(OrderedSet **module_set, const char *module) {
_cleanup_free_ char *m = NULL;
assert(module);
if (strdup_to(&m, module) < 0)
return log_oom();
return modules_list_append_suffix(module_set, TAKE_PTR(m));
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@ -39,31 +87,19 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return 0;
}
static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *pp = NULL;
int r;
static int apply_file(FILE *f, const char *filename, OrderedSet **module_set) {
int ret = 0, r;
assert(ctx);
assert(path);
assert(f);
r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f, &pp);
if (r < 0) {
if (ignore_enoent && r == -ENOENT)
return 0;
return log_error_errno(r, "Failed to open %s: %m", path);
}
log_debug("apply: %s", pp);
log_debug("apply: %s", filename);
for (;;) {
_cleanup_free_ char *line = NULL;
int k;
k = read_stripped_line(f, LONG_LINE_MAX, &line);
if (k < 0)
return log_error_errno(k, "Failed to read file '%s': %m", pp);
if (k == 0)
r = read_stripped_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read file '%s': %m", filename);
if (r == 0)
break;
if (isempty(line))
@ -71,21 +107,232 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
if (strchr(COMMENTS, *line))
continue;
k = module_load_and_warn(ctx, line, true);
if (k == -ENOENT)
continue;
RET_GATHER(r, k);
RET_GATHER(ret, modules_list_append_suffix(module_set, TAKE_PTR(line)));
}
return r;
return ret;
}
static int apply_file_from_path(const char *path, OrderedSet **module_set) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *pp = NULL;
int r;
assert(path);
r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f, &pp);
if (r < 0)
return log_error_errno(r, "Failed to open %s: %m", path);
return apply_file(f, pp, module_set);
}
static int apply_conf_file(ConfFile *c, OrderedSet **module_set) {
_cleanup_fclose_ FILE *f = NULL;
f = fopen(FORMAT_PROC_FD_PATH(c->fd), "re");
if (!f) {
if (errno == ENOENT)
return 0;
return log_error_errno(errno, "Failed to open %s: %m", c->original_path);
}
return apply_file(f, c->original_path, module_set);
}
static int do_direct_probe(OrderedSet *module_set) {
_cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
char *module;
int ret = 0, r;
r = module_setup_context(&ctx);
if (r < 0)
return log_error_errno(r, "Failed to initialize libkmod context: %m");
ORDERED_SET_FOREACH(module, module_set) {
r = module_load_and_warn(ctx, module, /* verbose = */ true);
if (r != -ENOENT)
RET_GATHER(ret, r);
}
return ret;
}
static int enqueue_module_to_load(int sock, const char *module) {
ssize_t bytes;
assert(sock >= 0);
assert(module);
bytes = send(sock, module, strlen(module), /* flags = */ 0);
if (bytes < 0)
return log_error_errno(errno, "Failed to send '%s' to thread pool: %m", module);
return 0;
}
static int dequeue_module_to_load(int sock, char *buffer, size_t buffer_len) {
ssize_t bytes;
assert(sock >= 0);
assert(buffer);
/* Dequeue one module to be loaded from the socket pair. In case no more
* modules are present, recv() will return 0. */
bytes = recv(sock, buffer, buffer_len, /* flags = */ 0);
if (bytes == 0)
return 0;
if (bytes < 0)
return negative_errno();
if ((size_t)bytes == buffer_len)
return -E2BIG;
buffer[bytes] = '\0';
return 1;
}
static int run_prober(int sock) {
_cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
char buffer[MODULE_NAME_MAX_LEN + 1];
int ret = 0, r;
r = module_setup_context(&ctx);
if (r < 0)
return log_error_errno(r, "Failed to initialize libkmod context: %m");
for (;;) {
r = dequeue_module_to_load(sock, buffer, sizeof(buffer));
if (ERRNO_IS_NEG_TRANSIENT(r))
continue;
if (r == -E2BIG) {
log_warning_errno(SYNTHETIC_ERRNO(E2BIG), "Dequeued module name too long, proceeding anyway");
continue;
}
if (r < 0)
return log_error_errno(r, "Failed to receive from module queue: %m");
if (r == 0) {
log_debug("No more queued modules, terminate thread");
break;
}
r = module_load_and_warn(ctx, buffer, /* verbose = */ true);
if (r != -ENOENT)
RET_GATHER(ret, r);
}
return ret;
}
static void *prober_thread(void *arg) {
int sock = PTR_TO_FD(arg);
return INT_TO_PTR(run_prober(sock));
}
static int create_worker_threads(size_t n_threads, void *arg, pthread_t **ret_threads, size_t *ret_n_threads) {
_cleanup_free_ pthread_t *new_threads = NULL;
size_t created_threads;
sigset_t ss, saved_ss;
int r;
assert(ret_threads);
assert(ret_n_threads);
if (n_threads == 0) {
*ret_threads = NULL;
*ret_n_threads = 0;
return 0;
}
/* Create worker threads with masked signals */
new_threads = new(pthread_t, n_threads);
if (!new_threads)
return log_oom();
/* No signals in worker threads. */
assert_se(sigfillset(&ss) >= 0);
r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
if (r != 0)
return log_error_errno(r, "Failed to mask signals for workers: %m");
for (created_threads = 0; created_threads < n_threads; ++created_threads) {
r = pthread_create(&new_threads[created_threads], /* attr = */ NULL, prober_thread, arg);
if (r != 0) {
log_error_errno(r, "Failed to create worker thread %zu: %m", created_threads);
break;
}
}
/* Restore the signal mask */
r = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
if (r != 0)
log_warning_errno(r, "Failed to restore signal mask, ignoring: %m");
*ret_threads = TAKE_PTR(new_threads);
*ret_n_threads = created_threads;
return 0;
}
static int destroy_worker_threads(pthread_t **threads, size_t n_threads) {
int ret = 0, r;
assert(threads);
assert(n_threads == 0 || *threads);
for (size_t i = 0; i < n_threads; ++i) {
void *p;
r = pthread_join((*threads)[i], &p);
if (r != 0)
RET_GATHER(ret, log_warning_errno(r, "Failed to join worker thread, proceeding anyway: %m"));
else
RET_GATHER(ret, PTR_TO_INT(p));
}
*threads = mfree(*threads);
return ret;
}
/* Determine number of workers, either from env or from online CPUs */
static unsigned determine_num_worker_threads(unsigned n_modules) {
unsigned n_threads = UINT_MAX;
int r;
if (n_modules == 0)
return 0;
const char *e = secure_getenv("SYSTEMD_MODULES_LOAD_NUM_THREADS");
if (e) {
r = safe_atou(e, &n_threads);
if (r < 0)
log_debug("Invalid value in $SYSTEMD_MODULES_LOAD_NUM_THREADS, ignoring: %s", e);
}
if (n_threads == UINT_MAX) {
/* By default, use a number of worker threads equal the number of online CPUs,
* but clamp it to avoid a probing storm on machines with many CPUs. */
long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
if (ncpus < 0) {
log_warning_errno(errno, "Failed to get number of online CPUs, ignoring: %m");
ncpus = 1;
}
n_threads = CLAMP((unsigned)ncpus, 1U, 16U);
}
/* There's no reason to spawn more threads than the modules that need to be loaded */
n_threads = CLAMP(n_threads, 1U, n_modules);
/* One of the probe threads is the main process */
return n_threads - 1U;
}
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-modules-load.service", "8", &link);
if (r < 0)
if (terminal_urlify_man("systemd-modules-load.service", "8", &link) < 0)
return log_oom();
printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
@ -135,8 +382,18 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
_cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
int r, k;
/* A OrderedSet instead of a plain Set is used here to make debug easier:
* in case a race condition is observed during module probing, the threading
* can be disabled through the SYSTEMD_MODULES_LOAD_NUM_THREADS environment
* variable and the modules reordered at will by the user that is debugging it.
* In that case, the probing order would be the same in which the modules
* appear inside the modules-load.d files (this wouldn't be true with a Set). */
_cleanup_ordered_set_free_ OrderedSet *module_set = NULL;
_cleanup_close_pair_ int pair[2] = EBADF_PAIR;
_cleanup_free_ pthread_t *threads = NULL;
size_t n_threads = 0;
char *module;
int ret = 0, r;
r = parse_argv(argc, argv);
if (r <= 0)
@ -146,39 +403,69 @@ static int run(int argc, char *argv[]) {
umask(0022);
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
r = proc_cmdline_parse(parse_proc_cmdline_item, /* userdata = */ NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
r = module_setup_context(&ctx);
if (r < 0)
return log_error_errno(r, "Failed to initialize libkmod context: %m");
r = 0;
if (argc > optind) {
for (int i = optind; i < argc; i++)
RET_GATHER(r, apply_file(ctx, argv[i], false));
for (int i = optind; i < argc; i++) {
r = apply_file_from_path(argv[i], &module_set);
if (r < 0)
RET_GATHER(ret, r);
}
} else {
_cleanup_strv_free_ char **files = NULL;
ConfFile **files = NULL;
size_t n_files = 0;
STRV_FOREACH(i, arg_proc_cmdline_modules) {
k = module_load_and_warn(ctx, *i, true);
if (k == -ENOENT)
continue;
RET_GATHER(r, k);
CLEANUP_ARRAY(files, n_files, conf_file_free_many);
STRV_FOREACH(i, arg_proc_cmdline_modules)
RET_GATHER(ret, modules_list_append_dup(&module_set, *i));
r = conf_files_list_nulstr_full(".conf", /* root = */ NULL,
CONF_FILES_REGULAR | CONF_FILES_FILTER_MASKED,
conf_file_dirs, &files, &n_files);
if (r < 0)
RET_GATHER(ret, log_error_errno(r, "Failed to enumerate modules-load.d files: %m"));
else
FOREACH_ARRAY(cf, files, n_files)
RET_GATHER(ret, apply_conf_file(*cf, &module_set));
}
k = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (k < 0)
return log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
n_threads = determine_num_worker_threads((size_t) ordered_set_size(module_set));
STRV_FOREACH(fn, files)
RET_GATHER(r, apply_file(ctx, *fn, true));
/* If no additional thread is required, there is no need to create the
* thread pool or the mean to communicate with its members. */
if (n_threads == 0) {
log_debug("Single-threaded probe");
return RET_GATHER(ret, do_direct_probe(module_set));
}
return r;
/* Create a socketpair for communication with probe workers */
r = RET_NERRNO(socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, /* protocol = */ 0, pair));
if (r < 0)
return log_error_errno(r, "Failed to create socket pair: %m");
/* Create threads, which will then wait for modules to probe. */
log_info("Using %zu probe threads", n_threads + 1);
r = create_worker_threads(n_threads, FD_TO_PTR(pair[1]), &threads, &n_threads);
if (r < 0)
log_warning_errno(r, "Failed to create probe threads, continuing as single-threaded probe");
/* Send modules to be probed */
ORDERED_SET_FOREACH(module, module_set)
RET_GATHER(ret, enqueue_module_to_load(pair[0], module));
/* Close one end of the socketpair; workers will run until the queue is empty */
pair[0] = safe_close(pair[0]);
/* Run the prober function also in original thread */
RET_GATHER(ret, run_prober(pair[1]));
/* Wait for all threads (if any) to finish and gather errors */
RET_GATHER(ret, destroy_worker_threads(&threads, n_threads));
return ret;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -1,11 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-bus.h"
#include "sd-varlink.h"
#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 "log.h"
@ -14,56 +11,34 @@
#include "networkctl-util.h"
#include "stdio-util.h"
#include "strv.h"
#include "varlink-util.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;
static int dump_manager_description(sd_varlink *vl) {
sd_json_variant *v;
int r;
assert(bus);
assert(ret);
assert(vl);
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);
r = varlink_call_and_log(vl, "io.systemd.Network.Describe", /* parameters = */ NULL, &v);
if (r < 0)
return r;
sd_json_variant_dump(v, arg_json_format_flags, NULL, NULL);
r = sd_json_variant_dump(v, arg_json_format_flags, /* f = */ NULL, /* prefix = */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to dump json object: %m");
return 0;
}
static int dump_link_description(sd_bus *bus, char * const *patterns) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
static int dump_link_description(sd_varlink *vl, char * const *patterns) {
_cleanup_free_ bool *matched_patterns = NULL;
sd_json_variant *i;
sd_json_variant *i, *v;
size_t c = 0;
int r;
assert(bus);
assert(vl);
assert(patterns);
r = get_description(bus, &v);
r = varlink_call_and_log(vl, "io.systemd.Network.Describe", /* parameters = */ NULL, &v);
if (r < 0)
return r;
@ -122,20 +97,20 @@ static int dump_link_description(sd_bus *bus, char * const *patterns) {
}
int dump_description(int argc, char *argv[]) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL;
int r;
if (!sd_json_format_enabled(arg_json_format_flags))
return 0;
r = acquire_bus(&bus);
r = varlink_connect_networkd(&vl);
if (r < 0)
return r;
if (arg_all || argc <= 1)
r = dump_manager_description(bus);
r = dump_manager_description(vl);
else
r = dump_link_description(bus, strv_skip(argv, 1));
r = dump_link_description(vl, strv_skip(argv, 1));
if (r < 0)
return r;

View File

@ -12,6 +12,7 @@
#include "lldp-rx-internal.h"
#include "network-util.h"
#include "networkd-dhcp-server.h"
#include "networkd-json.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-manager-varlink.h"
@ -20,6 +21,25 @@
#include "varlink-io.systemd.service.h"
#include "varlink-util.h"
static int vl_method_describe(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
Manager *m = ASSERT_PTR(userdata);
int r;
assert(parameters);
assert(link);
r = sd_varlink_dispatch(link, parameters, /* dispatch_table = */ NULL, /* userdata = */ NULL);
if (r != 0)
return r;
r = manager_build_json(m, &v);
if (r < 0)
return log_error_errno(r, "Failed to format JSON data: %m");
return sd_varlink_reply(link, v);
}
static int vl_method_get_states(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
int r;
@ -288,6 +308,7 @@ int manager_connect_varlink(Manager *m, int fd) {
r = sd_varlink_server_bind_method_many(
s,
"io.systemd.Network.Describe", vl_method_describe,
"io.systemd.Network.GetStates", vl_method_get_states,
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id,
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors,

View File

@ -345,7 +345,7 @@ static int extend_nvpcr_now(
"MESSAGE_ID=" SD_MESSAGE_TPM_NVPCR_EXTEND_STR,
LOG_MESSAGE("Extended NvPCR index '%s' with '%s'.", name, safe),
"MEASURING=%s", safe,
"NVPCR=%u", name);
"NVPCR=%s", name);
return 0;
}

View File

@ -827,7 +827,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
"Invalid hardlink path name '%s' in entry, refusing.", target);
_cleanup_close_ int target_fd = -EBADF;
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT, /* ret_path= */ NULL, &target_fd);
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW, /* ret_path= */ NULL, &target_fd);
if (r < 0)
return log_error_errno(
r,
@ -856,7 +856,7 @@ int tar_x(int input_fd, int tree_fd, TarFlags flags) {
_cleanup_close_ int target_parent_fd = -EBADF;
_cleanup_free_ char *target_filename = NULL;
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME, &target_filename, &target_parent_fd);
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME|CHASE_NOFOLLOW, &target_filename, &target_parent_fd);
if (r < 0)
return log_error_errno(
r,

View File

@ -2,47 +2,606 @@
#include "varlink-io.systemd.Network.h"
static SD_VARLINK_DEFINE_ENUM_TYPE(
LinkState,
SD_VARLINK_DEFINE_ENUM_VALUE(pending),
SD_VARLINK_DEFINE_ENUM_VALUE(initialized),
SD_VARLINK_DEFINE_ENUM_VALUE(configuring),
SD_VARLINK_DEFINE_ENUM_VALUE(configured),
SD_VARLINK_DEFINE_ENUM_VALUE(unmanaged),
SD_VARLINK_DEFINE_ENUM_VALUE(failed),
SD_VARLINK_DEFINE_ENUM_VALUE(linger));
SD_VARLINK_DEFINE_ENUM_TYPE(
LinkAddressState,
SD_VARLINK_DEFINE_ENUM_VALUE(off),
SD_VARLINK_DEFINE_ENUM_VALUE(degraded),
SD_VARLINK_DEFINE_ENUM_VALUE(routable));
SD_VARLINK_DEFINE_ENUM_TYPE(
LinkOnlineState,
SD_VARLINK_DEFINE_ENUM_VALUE(offline),
SD_VARLINK_DEFINE_ENUM_VALUE(partial),
SD_VARLINK_DEFINE_ENUM_VALUE(online));
SD_VARLINK_DEFINE_ENUM_TYPE(
LinkRequiredAddressFamily,
SD_VARLINK_DEFINE_ENUM_VALUE(any),
SD_VARLINK_DEFINE_ENUM_VALUE(ipv4),
SD_VARLINK_DEFINE_ENUM_VALUE(ipv6),
SD_VARLINK_DEFINE_ENUM_VALUE(both));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
RoutingPolicyRule,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Source address prefix to match"),
SD_VARLINK_DEFINE_FIELD(FromPrefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of source prefix in bits"),
SD_VARLINK_DEFINE_FIELD(FromPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Destination address prefix to match"),
SD_VARLINK_DEFINE_FIELD(ToPrefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of destination prefix in bits"),
SD_VARLINK_DEFINE_FIELD(ToPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Routing protocol identifier"),
SD_VARLINK_DEFINE_FIELD(Protocol, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable routing protocol name"),
SD_VARLINK_DEFINE_FIELD(ProtocolString, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Type of Service (TOS) field to match"),
SD_VARLINK_DEFINE_FIELD(TOS, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Rule action type (FR_ACT_* value)"),
SD_VARLINK_DEFINE_FIELD(Type, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable rule action type"),
SD_VARLINK_DEFINE_FIELD(TypeString, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("IP protocol number to match"),
SD_VARLINK_DEFINE_FIELD(IPProtocol, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable IP protocol name"),
SD_VARLINK_DEFINE_FIELD(IPProtocolString, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Rule priority (lower value means higher priority)"),
SD_VARLINK_DEFINE_FIELD(Priority, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Firewall mark value to match"),
SD_VARLINK_DEFINE_FIELD(FirewallMark, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Firewall mark mask to apply"),
SD_VARLINK_DEFINE_FIELD(FirewallMask, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Routing table number to use"),
SD_VARLINK_DEFINE_FIELD(Table, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable routing table name"),
SD_VARLINK_DEFINE_FIELD(TableString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether rule matching is inverted"),
SD_VARLINK_DEFINE_FIELD(Invert, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Suppress route lookup if prefix length is less than or equal to this value"),
SD_VARLINK_DEFINE_FIELD(SuppressPrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Suppress route lookup if interface group matches"),
SD_VARLINK_DEFINE_FIELD(SuppressInterfaceGroup, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Source port range to match [start, end]"),
SD_VARLINK_DEFINE_FIELD(SourcePort, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Destination port range to match [start, end]"),
SD_VARLINK_DEFINE_FIELD(DestinationPort, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("User ID range to match [start, end]"),
SD_VARLINK_DEFINE_FIELD(User, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Incoming interface name to match"),
SD_VARLINK_DEFINE_FIELD(IncomingInterface, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Outgoing interface name to match"),
SD_VARLINK_DEFINE_FIELD(OutgoingInterface, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this rule"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Configuration state of this rule"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Route,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Destination network address"),
SD_VARLINK_DEFINE_FIELD(Destination, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Destination network prefix length"),
SD_VARLINK_DEFINE_FIELD(DestinationPrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Gateway address for this route"),
SD_VARLINK_DEFINE_FIELD(Gateway, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Source address prefix for route selection"),
SD_VARLINK_DEFINE_FIELD(Source, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Source prefix length"),
SD_VARLINK_DEFINE_FIELD(SourcePrefixLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Preferred source address for outgoing packets"),
SD_VARLINK_DEFINE_FIELD(PreferredSource, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Type of Service (TOS) field"),
SD_VARLINK_DEFINE_FIELD(TOS, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Route scope (RT_SCOPE_* value)"),
SD_VARLINK_DEFINE_FIELD(Scope, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable scope string"),
SD_VARLINK_DEFINE_FIELD(ScopeString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Routing protocol identifier"),
SD_VARLINK_DEFINE_FIELD(Protocol, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable routing protocol name"),
SD_VARLINK_DEFINE_FIELD(ProtocolString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route type (RTN_* value)"),
SD_VARLINK_DEFINE_FIELD(Type, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable route type"),
SD_VARLINK_DEFINE_FIELD(TypeString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route priority/metric"),
SD_VARLINK_DEFINE_FIELD(Priority, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Routing table number"),
SD_VARLINK_DEFINE_FIELD(Table, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable routing table name"),
SD_VARLINK_DEFINE_FIELD(TableString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route flags (RTM_F_* values)"),
SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable flags string"),
SD_VARLINK_DEFINE_FIELD(FlagsString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Next hop ID for multipath routing"),
SD_VARLINK_DEFINE_FIELD(NextHopID, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Maximum Transmission Unit for this route"),
SD_VARLINK_DEFINE_FIELD(MTU, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route preference for IPv6 (low/medium/high)"),
SD_VARLINK_DEFINE_FIELD(Preference, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route lifetime in microseconds"),
SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this route"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration state of this route"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index for serialization"),
SD_VARLINK_DEFINE_FIELD(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Route metrics (RTAX_* values)"),
SD_VARLINK_DEFINE_FIELD(Metrics, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("TCP congestion control algorithm for this route"),
SD_VARLINK_DEFINE_FIELD(TCPCongestionControlAlgorithm, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NextHopGroup,
SD_VARLINK_FIELD_COMMENT("Next hop identifier in the multipath group"),
SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Weight for load balancing (higher means more traffic)"),
SD_VARLINK_DEFINE_FIELD(Weight, SD_VARLINK_INT, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NextHop,
SD_VARLINK_FIELD_COMMENT("Next hop identifier"),
SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Gateway address for this next hop"),
SD_VARLINK_DEFINE_FIELD(Gateway, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Next hop flags (RTNH_F_* values)"),
SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable flags string"),
SD_VARLINK_DEFINE_FIELD(FlagsString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Routing protocol identifier"),
SD_VARLINK_DEFINE_FIELD(Protocol, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable routing protocol name"),
SD_VARLINK_DEFINE_FIELD(ProtocolString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether this is a blackhole next hop (drops packets)"),
SD_VARLINK_DEFINE_FIELD(Blackhole, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Multipath group members with weights for load balancing"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Group, NextHopGroup, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this next hop"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration state of this next hop"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
LLDPNeighbor,
SD_VARLINK_FIELD_COMMENT("Chassis identifier in human-readable format"),
SD_VARLINK_DEFINE_FIELD(ChassisID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Raw chassis identifier bytes"),
SD_VARLINK_DEFINE_FIELD(RawChassisID, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Port identifier in human-readable format"),
SD_VARLINK_DEFINE_FIELD(PortID, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Raw port identifier bytes"),
SD_VARLINK_DEFINE_FIELD(RawPortID, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Description of the port"),
SD_VARLINK_DEFINE_FIELD(PortDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("System name of the LLDP neighbor"),
SD_VARLINK_DEFINE_FIELD(SystemName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("System description of the LLDP neighbor"),
SD_VARLINK_DEFINE_FIELD(SystemDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Enabled capabilities bitmap (bridge, router, WLAN, etc.)"),
SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Manufacturer Usage Description URL (RFC8520)"),
SD_VARLINK_DEFINE_FIELD(MUDURL, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("VLAN identifier"),
SD_VARLINK_DEFINE_FIELD(VlanID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNS,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("DNS server IP address"),
SD_VARLINK_DEFINE_FIELD(Address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("DNS server port number"),
SD_VARLINK_DEFINE_FIELD(Port, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index for link-local DNS servers"),
SD_VARLINK_DEFINE_FIELD(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS server hostname for DoT/DoH"),
SD_VARLINK_DEFINE_FIELD(ServerName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this DNS server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NTP,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("NTP server IP address"),
SD_VARLINK_DEFINE_FIELD(Address, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("NTP server"),
SD_VARLINK_DEFINE_FIELD(Server, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this NTP server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
SIP,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6) for address-based servers"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("SIP server IP address"),
SD_VARLINK_DEFINE_FIELD(Address, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("SIP server domain name"),
SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this SIP server"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Domain,
SD_VARLINK_FIELD_COMMENT("DNS search or route domain name"),
SD_VARLINK_DEFINE_FIELD(Domain, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Configuration source for this domain"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSSECNegativeTrustAnchor,
SD_VARLINK_FIELD_COMMENT("Domain name for which DNSSEC validation is disabled"),
SD_VARLINK_DEFINE_FIELD(DNSSECNegativeTrustAnchor, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Configuration source for this negative trust anchor"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSSetting,
SD_VARLINK_FIELD_COMMENT("Link-Local Multicast Name Resolution setting"),
SD_VARLINK_DEFINE_FIELD(LLMNR, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Multicast DNS setting"),
SD_VARLINK_DEFINE_FIELD(MDNS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether this connection can be used as a default route for DNS lookups"),
SD_VARLINK_DEFINE_FIELD(DNSDefaultRoute, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS-over-TLS mode setting"),
SD_VARLINK_DEFINE_FIELD(DNSOverTLS, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Configuration source for this DNS setting"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Pref64,
SD_VARLINK_FIELD_COMMENT("IPv6 prefix for NAT64/DNS64"),
SD_VARLINK_DEFINE_FIELD(Prefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of the prefix in bits"),
SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Lifetime of the prefix in microseconds"),
SD_VARLINK_DEFINE_FIELD(LifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address of router that provided this prefix"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
NDisc,
SD_VARLINK_FIELD_COMMENT("PREF64 (RFC8781) prefixes advertised via IPv6 Router Advertisements"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(PREF64, Pref64, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Address,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("IP address"),
SD_VARLINK_DEFINE_FIELD(Address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Peer address for point-to-point interfaces"),
SD_VARLINK_DEFINE_FIELD(Peer, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Network prefix length"),
SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Configuration source for this address"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address of the configuration provider (DHCP server, router, etc.)"),
SD_VARLINK_DEFINE_FIELD(ConfigProvider, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Broadcast address for IPv4 networks"),
SD_VARLINK_DEFINE_FIELD(Broadcast, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address scope (RT_SCOPE_* value)"),
SD_VARLINK_DEFINE_FIELD(Scope, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable scope string"),
SD_VARLINK_DEFINE_FIELD(ScopeString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address flags (IFA_F_* values)"),
SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable flags string"),
SD_VARLINK_DEFINE_FIELD(FlagsString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address label for IPv4"),
SD_VARLINK_DEFINE_FIELD(Label, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Preferred lifetime in microseconds"),
SD_VARLINK_DEFINE_FIELD(PreferredLifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Preferred lifetime in microseconds (deprecated, for backward compatibility)"),
SD_VARLINK_DEFINE_FIELD(PreferredLifetimeUsec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), /* for backward compat */
SD_VARLINK_FIELD_COMMENT("Valid lifetime in microseconds"),
SD_VARLINK_DEFINE_FIELD(ValidLifetimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Valid lifetime in microseconds (deprecated, for backward compatibility)"),
SD_VARLINK_DEFINE_FIELD(ValidLifetimeUsec, SD_VARLINK_INT, SD_VARLINK_NULLABLE), /* for backward compat */
SD_VARLINK_FIELD_COMMENT("Configuration state of this address"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Neighbor,
SD_VARLINK_FIELD_COMMENT("Address family (AF_INET or AF_INET6)"),
SD_VARLINK_DEFINE_FIELD(Family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("IP address of the neighbor"),
SD_VARLINK_DEFINE_FIELD(Destination, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Link layer (MAC) address of the neighbor"),
SD_VARLINK_DEFINE_FIELD(LinkLayerAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Configuration source for this neighbor entry"),
SD_VARLINK_DEFINE_FIELD(ConfigSource, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Configuration state of this neighbor entry"),
SD_VARLINK_DEFINE_FIELD(ConfigState, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPLease,
SD_VARLINK_FIELD_COMMENT("Timestamp when the lease was acquired in microseconds"),
SD_VARLINK_DEFINE_FIELD(LeaseTimestampUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("T1 timeout (lease renewal time) in microseconds"),
SD_VARLINK_DEFINE_FIELD(Timeout1USec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("T2 timeout (lease rebinding time) in microseconds"),
SD_VARLINK_DEFINE_FIELD(Timeout2USec, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
PrivateOption,
SD_VARLINK_FIELD_COMMENT("DHCP option number"),
SD_VARLINK_DEFINE_FIELD(Option, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Raw data of the private DHCP option"),
SD_VARLINK_DEFINE_FIELD(PrivateOptionData, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPv6ClientPD,
SD_VARLINK_FIELD_COMMENT("Delegated IPv6 prefix"),
SD_VARLINK_DEFINE_FIELD(Prefix, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of the delegated prefix in bits"),
SD_VARLINK_DEFINE_FIELD(PrefixLength, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Preferred lifetime of the prefix in microseconds"),
SD_VARLINK_DEFINE_FIELD(PreferredLifetimeUsec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Valid lifetime of the prefix in microseconds"),
SD_VARLINK_DEFINE_FIELD(ValidLifetimeUsec, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPv6ClientVendorOption,
SD_VARLINK_FIELD_COMMENT("IANA enterprise number identifying the vendor"),
SD_VARLINK_DEFINE_FIELD(EnterpriseId, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Vendor-specific sub-option code"),
SD_VARLINK_DEFINE_FIELD(SubOptionCode, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Raw data of the vendor-specific sub-option"),
SD_VARLINK_DEFINE_FIELD(SubOptionData, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPv6Client,
SD_VARLINK_FIELD_COMMENT("DHCPv6 lease information including timestamps and timeouts"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Lease, DHCPLease, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Delegated prefixes received from DHCPv6 server"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Prefixes, DHCPv6ClientPD, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Vendor-specific options received in DHCPv6 response"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(VendorSpecificOptions, DHCPv6ClientVendorOption, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DHCP Unique Identifier (DUID) of the client"),
SD_VARLINK_DEFINE_FIELD(DUID, SD_VARLINK_INT, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPServerLease,
SD_VARLINK_FIELD_COMMENT("DHCP client identifier"),
SD_VARLINK_DEFINE_FIELD(ClientId, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Address assigned to the client"),
SD_VARLINK_DEFINE_FIELD(Address, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hostname provided by the DHCP client"),
SD_VARLINK_DEFINE_FIELD(Hostname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hardware address type (ARPHRD_* value)"),
SD_VARLINK_DEFINE_FIELD(HardwareAddressType, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Length of hardware address in bytes"),
SD_VARLINK_DEFINE_FIELD(HardwareAddressLength, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hardware (MAC) address of the DHCP client"),
SD_VARLINK_DEFINE_FIELD(HardwareAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Lease expiration time in monotonic microseconds"),
SD_VARLINK_DEFINE_FIELD(ExpirationUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Lease expiration time in realtime microseconds"),
SD_VARLINK_DEFINE_FIELD(ExpirationRealtimeUSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DHCPServer,
SD_VARLINK_FIELD_COMMENT("Offset from the network address for the DHCP address pool"),
SD_VARLINK_DEFINE_FIELD(PoolOffset, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Size of the DHCP address pool"),
SD_VARLINK_DEFINE_FIELD(PoolSize, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Active DHCP leases assigned by the server"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Leases, DHCPServerLease, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Static DHCP leases configured for specific clients"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(StaticLeases, DHCPServerLease, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
Interface,
SD_VARLINK_FIELD_COMMENT("Network interface index"),
SD_VARLINK_DEFINE_FIELD(Index, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Primary interface name"),
SD_VARLINK_DEFINE_FIELD(Name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Alternative interface names"),
SD_VARLINK_DEFINE_FIELD(AlternativeNames, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index of the master device (for bridge/bond slaves)"),
SD_VARLINK_DEFINE_FIELD(MasterInterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface kind (vlan, bridge, bond, etc.)"),
SD_VARLINK_DEFINE_FIELD(Kind, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface type (ether, loopback, etc.)"),
SD_VARLINK_DEFINE_FIELD(Type, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Kernel driver name"),
SD_VARLINK_DEFINE_FIELD(Driver, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface flags (IFF_* values)"),
SD_VARLINK_DEFINE_FIELD(Flags, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable interface flags"),
SD_VARLINK_DEFINE_FIELD(FlagsString, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Kernel operational state (IF_OPER_* value)"),
SD_VARLINK_DEFINE_FIELD(KernelOperationalState, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Human-readable kernel operational state"),
SD_VARLINK_DEFINE_FIELD(KernelOperationalStateString, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Current MTU in bytes"),
SD_VARLINK_DEFINE_FIELD(MTU, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Minimum allowed MTU in bytes"),
SD_VARLINK_DEFINE_FIELD(MinimumMTU, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Maximum allowed MTU in bytes"),
SD_VARLINK_DEFINE_FIELD(MaximumMTU, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Current hardware (MAC) address"),
SD_VARLINK_DEFINE_FIELD(HardwareAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Permanent hardware (MAC) address from factory"),
SD_VARLINK_DEFINE_FIELD(PermanentHardwareAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Broadcast address for Ethernet interfaces"),
SD_VARLINK_DEFINE_FIELD(BroadcastAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("IPv6 link-local address"),
SD_VARLINK_DEFINE_FIELD(IPv6LinkLocalAddress, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Wireless LAN interface type (NL80211_IFTYPE_* value)"),
SD_VARLINK_DEFINE_FIELD(WirelessLanInterfaceType, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Human-readable wireless LAN interface type"),
SD_VARLINK_DEFINE_FIELD(WirelessLanInterfaceTypeString, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Wireless network SSID"),
SD_VARLINK_DEFINE_FIELD(SSID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Wireless access point BSSID (MAC address)"),
SD_VARLINK_DEFINE_FIELD(BSSID, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Administrative state (configuring, configured, etc.)"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(AdministrativeState, LinkState, 0),
SD_VARLINK_FIELD_COMMENT("Operational state (routable, degraded, etc.)"),
SD_VARLINK_DEFINE_FIELD(OperationalState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Carrier state (carrier, no-carrier, etc.)"),
SD_VARLINK_DEFINE_FIELD(CarrierState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Address configuration state"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("IPv4 address configuration state"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(IPv4AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("IPv6 address configuration state"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(IPv6AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("Online state (online, offline, etc.)"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(OnlineState, LinkOnlineState, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Path to .network configuration file"),
SD_VARLINK_DEFINE_FIELD(NetworkFile, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Paths to .network drop-in configuration files"),
SD_VARLINK_DEFINE_FIELD(NetworkFileDropins, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether this interface is required for online state"),
SD_VARLINK_DEFINE_FIELD(RequiredForOnline, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Required operational state range for considering interface online [min, max]"),
SD_VARLINK_DEFINE_FIELD(RequiredOperationalStateForOnline, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Required address family for considering interface online"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(RequiredFamilyForOnline, LinkRequiredAddressFamily, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Activation policy (up, always-up, manual, etc.)"),
SD_VARLINK_DEFINE_FIELD(ActivationPolicy, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Path to .netdev configuration file"),
SD_VARLINK_DEFINE_FIELD(NetDevFile, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Paths to .netdev drop-in configuration files"),
SD_VARLINK_DEFINE_FIELD(NetDevFileDropins, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Path to .link configuration file"),
SD_VARLINK_DEFINE_FIELD(LinkFile, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Paths to .link drop-in configuration files"),
SD_VARLINK_DEFINE_FIELD(LinkFileDropins, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Device path in sysfs"),
SD_VARLINK_DEFINE_FIELD(Path, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hardware vendor name"),
SD_VARLINK_DEFINE_FIELD(Vendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Hardware model name"),
SD_VARLINK_DEFINE_FIELD(Model, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS servers configured for this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(DNS, DNS, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
/* FIXME: DNR Addresses fied (json array or arrays) is incompatible with Varlink type system */
SD_VARLINK_FIELD_COMMENT("Discovery of Network-designated Resolvers (RFC9463)"),
SD_VARLINK_DEFINE_FIELD(DNR, SD_VARLINK_OBJECT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("NTP servers configured for this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(NTP, NTP, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("SIP servers configured for this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(SIP, SIP, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS search domains"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(SearchDomains, Domain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS route-only domains"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(RouteDomains, Domain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNSSEC negative trust anchors"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(DNSSECNegativeTrustAnchors, DNSSECNegativeTrustAnchor, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS resolution settings (LLMNR, mDNS, etc.)"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(DNSSettings, DNSSetting, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Captive portal detection URL (RFC8910)"),
SD_VARLINK_DEFINE_FIELD(CaptivePortal, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("IPv6 Neighbor Discovery information"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(NDisc, NDisc, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("IP addresses configured on this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Addresses, Address, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Neighbor entries (ARP/NDP cache)"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Neighbors, Neighbor, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Next hops for multipath routing"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(NextHops, NextHop, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Routes configured on this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Routes, Route, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DHCP server configuration and leases"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(DHCPServer, DHCPServer, SD_VARLINK_NULLABLE),
/* FIXME: DHCPv4Client has 6rdPrefix field that is incompatible with Varlink naming */
SD_VARLINK_FIELD_COMMENT("DHCPv4 client configuration and lease information"),
SD_VARLINK_DEFINE_FIELD(DHCPv4Client, SD_VARLINK_OBJECT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DHCPv6 client configuration and lease information"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(DHCPv6Client, DHCPv6Client, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLDP neighbors discovered on this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(LLDP, LLDPNeighbor, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
Describe,
SD_VARLINK_FIELD_COMMENT("All network interfaces managed by systemd-networkd"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Interfaces, Interface, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("All configured next hops for multipath routing"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(NextHops, NextHop, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("All configured routes across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Routes, Route, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("All configured routing policy rules"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(RoutingPolicyRules, RoutingPolicyRule, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD(
GetStates,
SD_VARLINK_DEFINE_OUTPUT(AddressState, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_OUTPUT(IPv4AddressState, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_OUTPUT(IPv6AddressState, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Overall address configuration state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("IPv4 address configuration state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(IPv4AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("IPv6 address configuration state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(IPv6AddressState, LinkAddressState, 0),
SD_VARLINK_FIELD_COMMENT("Carrier state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT(CarrierState, SD_VARLINK_STRING, 0),
SD_VARLINK_DEFINE_OUTPUT(OnlineState, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Online state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(OnlineState, LinkOnlineState, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Operational state across all interfaces"),
SD_VARLINK_DEFINE_OUTPUT(OperationalState, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_METHOD(
GetNamespaceId,
SD_VARLINK_FIELD_COMMENT("Network namespace inode number"),
SD_VARLINK_DEFINE_OUTPUT(NamespaceId, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Network namespace ID (cookie) assigned by the kernel"),
SD_VARLINK_DEFINE_OUTPUT(NamespaceNSID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
LLDPNeighbor,
SD_VARLINK_DEFINE_FIELD(ChassisID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(RawChassisID, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_DEFINE_FIELD(PortID, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(RawPortID, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_DEFINE_FIELD(PortDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(SystemName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(SystemDescription, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(EnabledCapabilities, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(VlanID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
LLDPNeighborsByInterface,
SD_VARLINK_FIELD_COMMENT("Network interface index"),
SD_VARLINK_DEFINE_FIELD(InterfaceIndex, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Primary interface name"),
SD_VARLINK_DEFINE_FIELD(InterfaceName, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Alternative interface names"),
SD_VARLINK_DEFINE_FIELD(InterfaceAlternativeNames, SD_VARLINK_STRING, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLDP neighbors discovered on this interface"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(Neighbors, LLDPNeighbor, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_METHOD(
GetLLDPNeighbors,
SD_VARLINK_FIELD_COMMENT("Filter by interface index (optional)"),
SD_VARLINK_DEFINE_INPUT(InterfaceIndex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Filter by interface name (optional)"),
SD_VARLINK_DEFINE_INPUT(InterfaceName, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("LLDP neighbors grouped by interface"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(Neighbors, LLDPNeighborsByInterface, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_METHOD(
SetPersistentStorage,
SD_VARLINK_FIELD_COMMENT("Whether persistent storage is ready and writable"),
SD_VARLINK_DEFINE_INPUT(Ready, SD_VARLINK_BOOL, 0));
static SD_VARLINK_DEFINE_ERROR(StorageReadOnly);
@ -50,10 +609,37 @@ static SD_VARLINK_DEFINE_ERROR(StorageReadOnly);
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Network,
"io.systemd.Network",
&vl_method_Describe,
&vl_method_GetStates,
&vl_method_GetNamespaceId,
&vl_method_GetLLDPNeighbors,
&vl_method_SetPersistentStorage,
&vl_type_Address,
&vl_type_DHCPLease,
&vl_type_DHCPServer,
&vl_type_DHCPServerLease,
&vl_type_DHCPv6Client,
&vl_type_DHCPv6ClientPD,
&vl_type_DHCPv6ClientVendorOption,
&vl_type_DNS,
&vl_type_DNSSECNegativeTrustAnchor,
&vl_type_DNSSetting,
&vl_type_Domain,
&vl_type_Interface,
&vl_type_LinkState,
&vl_type_LinkAddressState,
&vl_type_LinkOnlineState,
&vl_type_LinkRequiredAddressFamily,
&vl_type_LLDPNeighbor,
&vl_type_LLDPNeighborsByInterface,
&vl_type_NDisc,
&vl_type_Neighbor,
&vl_type_NextHop,
&vl_type_NextHopGroup,
&vl_type_NTP,
&vl_type_Pref64,
&vl_type_PrivateOption,
&vl_type_Route,
&vl_type_RoutingPolicyRule,
&vl_type_SIP,
&vl_error_StorageReadOnly);

View File

@ -4,3 +4,6 @@
#include "sd-varlink-idl.h"
extern const sd_varlink_interface vl_interface_io_systemd_Network;
extern const sd_varlink_symbol vl_type_LinkAddressState;
extern const sd_varlink_symbol vl_type_LinkOnlineState;
extern const sd_varlink_symbol vl_type_LinkRequiredAddressFamily;

View File

@ -11,6 +11,7 @@
#include "dissect-image.h"
#include "fd-util.h"
#include "json-util.h"
#include "network-util.h"
#include "pretty-print.h"
#include "tests.h"
#include "varlink-idl-util.h"
@ -512,6 +513,12 @@ TEST(enums_idl) {
TEST_IDL_ENUM(BootEntryType, boot_entry_type, vl_type_BootEntryType);
TEST_IDL_ENUM_TO_STRING(BootEntrySource, boot_entry_source, vl_type_BootEntrySource);
TEST_IDL_ENUM(PartitionDesignator, partition_designator, vl_type_PartitionDesignator);
TEST_IDL_ENUM(LinkAddressState, link_address_state, vl_type_LinkAddressState);
TEST_IDL_ENUM_TO_STRING(LinkAddressState, link_address_state, vl_type_LinkAddressState);
TEST_IDL_ENUM(LinkOnlineState, link_online_state, vl_type_LinkOnlineState);
TEST_IDL_ENUM_TO_STRING(LinkOnlineState, link_online_state, vl_type_LinkOnlineState);
TEST_IDL_ENUM(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily);
TEST_IDL_ENUM_TO_STRING(AddressFamily, link_required_address_family, vl_type_LinkRequiredAddressFamily);
}
DEFINE_TEST_MAIN(LOG_DEBUG);

View File

@ -175,9 +175,15 @@ chattr +A /home/testuser/.local/state/machines/inodetest/testfile
chown foreign-0:foreign-0 /home/testuser/.local/state/machines/inodetest/testfile.hard /home/testuser/.local/state/machines/inodetest
ls -al /home/testuser/.local/state/machines/inodetest
# Verify UID squashing
echo gaga > /home/testuser/.local/state/machines/inodetest/squashtest
chown 1000:1000 /home/testuser/.local/state/machines/inodetest/squashtest
# Ensure hardlinked symlinks work
ln -s sometarget /home/testuser/.local/state/machines/inodetest/testfile.sym
ln /home/testuser/.local/state/machines/inodetest/testfile.sym /home/testuser/.local/state/machines/inodetest/testfile.symhard
chown -h foreign-0:foreign-0 /home/testuser/.local/state/machines/inodetest/testfile.symhard
run0 --pipe -u testuser importctl -m --user export-tar inodetest |
run0 --pipe -u testuser importctl -m --user import-tar - inodetest2
@ -199,7 +205,11 @@ cmp <(lsattr /home/testuser/.local/state/machines/inodetest/testfile | cut -d "
# verify that squashing outside of 64K works
test "$(stat -c'%U:%G' /home/testuser/.local/state/machines/inodetest2/squashtest)" = "foreign-65534:foreign-65534"
# chown to foreing UID range, so that removal works
# Verify that the hardlinked symlink is restored as such
cmp <(stat -c"%i" /home/testuser/.local/state/machines/inodetest2/testfile.sym) <(stat -c"%i" /home/testuser/.local/state/machines/inodetest2/testfile.symhard)
test "$(readlink /home/testuser/.local/state/machines/inodetest2/testfile.symhard)" = "sometarget"
# chown to foreign UID range, so that removal works
chown foreign-4711:foreign-4711 /home/testuser/.local/state/machines/inodetest/squashtest
run0 -u testuser machinectl --user remove inodetest

View File

@ -185,6 +185,11 @@ varlinkctl info /run/systemd/io.systemd.Manager
varlinkctl introspect /run/systemd/io.systemd.Manager io.systemd.Manager
varlinkctl call /run/systemd/io.systemd.Manager io.systemd.Manager.Describe '{}'
# test io.systemd.Network
varlinkctl info /run/systemd/netif/io.systemd.Network
varlinkctl introspect /run/systemd/netif/io.systemd.Network io.systemd.Network
varlinkctl call /run/systemd/netif/io.systemd.Network io.systemd.Network.Describe '{}'
# test io.systemd.Unit
varlinkctl info /run/systemd/io.systemd.Manager
varlinkctl introspect /run/systemd/io.systemd.Manager io.systemd.Unit

View File

@ -50,17 +50,22 @@ dummy
dumm!@@123##2455
# This is a comment
$(printf "%.0sx" {0..4096})
$(printf "%.0sx" {1..4096})
dummy
dummy
foo-bar-baz
foo_bar_baz
foo_bar-baz
1
"
'
EOF
"$MODULES_LOAD_BIN" |& tee /tmp/out.log
grep -E "^Inserted module .*dummy" /tmp/out.log
grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log
# Module names are "normalized", i.e., dashes are converted to underscores
grep -E "^Failed to find module .*foo_bar_baz" /tmp/out.log
(! grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log)
(! grep -E "^Failed to find module .*foo_bar-baz" /tmp/out.log)
(! grep -E "This is a comment" /tmp/out.log)
# Each module should be loaded only once, even if specified multiple times
[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 1 ]]
@ -75,7 +80,9 @@ rm -fv "$CONFIG_FILE"
CMDLINE="ro root= modules_load= modules_load=, / = modules_load=foo-bar-baz,dummy modules_load=dummy,dummy,dummy"
SYSTEMD_PROC_CMDLINE="$CMDLINE" "$MODULES_LOAD_BIN" |& tee /tmp/out.log
grep -E "^Inserted module .*dummy" /tmp/out.log
grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log
# Module names are "normalized", i.e., dashes are converted to underscores
(! grep -E "^Failed to find module .*foo-bar-baz" /tmp/out.log)
grep -E "^Failed to find module .*foo_bar_baz" /tmp/out.log
# Each module should be loaded only once, even if specified multiple times
[[ "$(grep -Ec "^Inserted module" /tmp/out.log)" -eq 1 ]]