shared: move machine registration to shared machine-register.{c,h}

Move register_machine() and unregister_machine() from
vmspawn-register.{c,h} into shared machine-register.{c,h} so both
nspawn and vmspawn can use the same implementation.

The unified register_machine() uses varlink first (for richer
features like SSH support and unit allocation) with a D-Bus
RegisterMachineWithNetwork fallback for older machined. The
interface adds a class parameter ("vm" or "container") and
local_ifindex for nspawn's network interface support.

The unified unregister_machine() similarly tries varlink first
(io.systemd.Machine.Unregister) before falling back to D-Bus.

Both register_machine() and unregister_machine() only log at debug
level internally, leaving error/notice logging to callers.

Add register_machine_with_fallback() which tries system and/or user
scope registration based on a RuntimeScope parameter
(_RUNTIME_SCOPE_INVALID for both), and
unregister_machine_with_fallback() as its counterpart. Both use
RET_GATHER() to collect errors from each scope.

Make --register= a tristate (yes/no/auto) defaulting to auto. When
set to auto, registration failures are logged at notice level and
ignored. When set to yes, failures are fatal.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daan De Meyer
2026-04-06 17:13:40 +02:00
committed by Daan De Meyer
parent 0e231729fd
commit 1e084aad7d
15 changed files with 493 additions and 375 deletions
+5 -5
View File
@@ -781,14 +781,14 @@
<listitem><para>Controls whether the container is registered with
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Takes a
boolean argument, which defaults to <literal>yes</literal>. This option should be enabled when the container
runs a full Operating System (more specifically: a system and service manager as PID 1), and is useful to
ensure that the container is accessible via
boolean argument or <literal>auto</literal>, and defaults to <literal>auto</literal>. This option should be
enabled when the container runs a full Operating System (more specifically: a system and service manager as
PID 1), and is useful to ensure that the container is accessible via
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> and shown by
tools such as <citerefentry
project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If the container
does not run a service manager, it is recommended to set this option to
<literal>no</literal>.</para>
does not run a service manager, it is recommended to set this option to <literal>no</literal>. When set to
<literal>auto</literal>, registration is attempted but failures are ignored.</para>
<xi:include href="version-info.xml" xpointer="v209"/></listitem>
</varlistentry>
+4 -7
View File
@@ -501,13 +501,10 @@
<listitem><para>Controls whether the virtual machine is registered with
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Takes a
boolean argument, which defaults to <literal>yes</literal> when running as root, and <literal>no</literal> when
running as a regular user. This ensures that the virtual machine is accessible via
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
<para>Note: root privileges are required to use this option as registering with
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>
requires privileged D-Bus method calls.</para>
boolean argument or <literal>auto</literal>, and defaults to <literal>auto</literal>. This ensures that the
virtual machine is accessible via
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. When set to
<literal>auto</literal>, registration is attempted but failures are ignored.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
</varlistentry>
+1 -1
View File
@@ -131,7 +131,7 @@ _systemd_nspawn() {
comps=''
;;
--register)
comps='yes no'
comps='yes no auto'
;;
--network-interface)
comps=$(__get_interfaces)
+3 -3
View File
@@ -31,8 +31,8 @@ _systemd_vmspawn() {
local -A OPTS=(
[STANDALONE]='-h --help --version -q --quiet --no-pager -n --network-tap --network-user-mode --user --system -x --ephemeral'
[PATH]='-D --directory -i --image --linux --initrd --extra-drive --forward-journal --efi-nvram-template'
[BOOL]='--kvm --cxl --vsock --tpm --discard-disk --register --pass-ssh-key'
[SECURE_BOOT]='--secure-boot'
[BOOL]='--kvm --cxl --vsock --tpm --discard-disk --pass-ssh-key'
[TRISTATE]='--register --secure-boot'
[FIRMWARE]='--firmware'
[FIRMWARE_FEATURES]='--firmware-features'
[BIND]='--bind --bind-ro'
@@ -47,7 +47,7 @@ _systemd_vmspawn() {
if __contains_word "$prev" ${OPTS[BOOL]}; then
comps='yes no'
elif __contains_word "$prev" ${OPTS[SECURE_BOOT]}; then
elif __contains_word "$prev" ${OPTS[TRISTATE]}; then
comps='yes no auto'
elif __contains_word "$prev" ${OPTS[PATH]}; then
compopt -o nospace -o filenames
+1 -1
View File
@@ -45,7 +45,7 @@ _arguments \
'--tmpfs=[Mount an empty tmpfs to the specified directory.]: : _files' \
'--setenv=[Specifies an environment variable assignment to pass to the init process in the container, in the format "NAME=VALUE".]: : _message "environment variables"' \
'--share-system[Allows the container to share certain system facilities with the host.]' \
'--register=[Controls whether the container is registered with systemd-machined(8).]:systemd-machined registration:( yes no )' \
'--register=[Controls whether the container is registered with systemd-machined(8).]:systemd-machined registration:( yes no auto )' \
'--keep-unit[Instead of creating a transient scope unit to run the container in, simply register the service or scope unit systemd-nspawn has been invoked in with systemd-machined(8).]' \
'--personality=[Control the architecture ("personality") reported by uname(2) in the container.]:architecture:(x86 x86-64)' \
'--volatile=[Run the system in volatile mode.]:volatile:(no yes state)' \
-144
View File
@@ -131,150 +131,6 @@ static int can_set_coredump_receive(sd_bus *bus) {
return r >= 0;
}
static int register_machine_ex(
sd_bus *bus,
const char *machine_name,
const PidRef *pid,
const char *directory,
sd_id128_t uuid,
int local_ifindex,
const char *service,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
int r;
assert(bus);
assert(machine_name);
assert(service);
assert(error);
r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RegisterMachineEx");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", machine_name);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"(sv)(sv)(sv)",
"Id", "ay", SD_BUS_MESSAGE_APPEND_ID128(uuid),
"Service", "s", service,
"Class", "s", "container");
if (r < 0)
return bus_log_create_error(r);
if (pidref_is_set(pid)) {
if (pid->fd >= 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFD", "h", pid->fd);
if (r < 0)
return bus_log_create_error(r);
}
if (pid->fd_id > 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFDID", "t", pid->fd_id);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "(sv)", "LeaderPID", "u", pid->pid);
if (r < 0)
return bus_log_create_error(r);
}
}
if (!isempty(directory)) {
r = sd_bus_message_append(m, "(sv)", "RootDirectory", "s", directory);
if (r < 0)
return bus_log_create_error(r);
}
if (local_ifindex > 0) {
r = sd_bus_message_append(m, "(sv)", "NetworkInterfaces", "ai", 1, local_ifindex);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
return sd_bus_call(bus, m, 0, error, NULL);
}
int register_machine(
sd_bus *bus,
const char *machine_name,
const PidRef *pid,
const char *directory,
sd_id128_t uuid,
int local_ifindex,
const char *service) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
assert(machine_name);
assert(service);
r = register_machine_ex(
bus,
machine_name,
pid,
directory,
uuid,
local_ifindex,
service,
&error);
if (r >= 0)
return 0;
if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
sd_bus_error_free(&error);
r = bus_call_method(
bus,
bus_machine_mgr,
"RegisterMachineWithNetwork",
&error,
NULL,
"sayssusai",
machine_name,
SD_BUS_MESSAGE_APPEND_ID128(uuid),
service,
"container",
pidref_is_set(pid) ? (uint32_t) pid->pid : 0,
strempty(directory),
local_ifindex > 0 ? 1 : 0, local_ifindex);
if (r < 0)
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
return 0;
}
int unregister_machine(
sd_bus *bus,
const char *machine_name) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
if (r < 0)
log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
return 0;
}
int allocate_scope(
sd_bus *bus,
const char *machine_name,
-10
View File
@@ -4,16 +4,6 @@
#include "shared-forward.h"
#include "nspawn-settings.h"
int register_machine(
sd_bus *bus,
const char *machine_name,
const PidRef *pid,
const char *directory,
sd_id128_t uuid,
int local_ifindex,
const char *service);
int unregister_machine(sd_bus *bus, const char *machine_name);
typedef enum AllocateScopeFlags {
ALLOCATE_SCOPE_ALLOW_PIDFD = 1 << 0,
} AllocateScopeFlags;
+22 -37
View File
@@ -66,6 +66,7 @@
#include "loopback-setup.h"
#include "machine-bind-user.h"
#include "machine-credential.h"
#include "machine-register.h"
#include "main-func.h"
#include "mkdir.h"
#include "mount-util.h"
@@ -192,7 +193,7 @@ static CustomMount *arg_custom_mounts = NULL;
static size_t arg_n_custom_mounts = 0;
static char **arg_setenv = NULL;
static bool arg_quiet = false;
static bool arg_register = true;
static int arg_register = -1;
static bool arg_keep_unit = false;
static char **arg_network_interfaces = NULL;
static char **arg_network_macvlan = NULL;
@@ -1163,7 +1164,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_REGISTER:
r = parse_boolean_argument("--register=", optarg, &arg_register);
r = parse_tristate_argument_with_auto("--register=", optarg, &arg_register);
if (r < 0)
return r;
@@ -5613,7 +5614,7 @@ static int run_container(
/* Registration always happens on the system bus */
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
if (arg_register || (arg_privileged && !arg_keep_unit)) {
if (arg_register != 0 || (arg_privileged && !arg_keep_unit)) {
r = sd_bus_default_system(&system_bus);
if (r < 0)
return log_error_errno(r, "Failed to open system bus: %m");
@@ -5628,7 +5629,7 @@ static int run_container(
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *user_bus = NULL;
_cleanup_(sd_bus_unrefp) sd_bus *runtime_bus = NULL;
if (arg_register || !arg_keep_unit) {
if (arg_register != 0 || !arg_keep_unit) {
if (arg_privileged)
runtime_bus = sd_bus_ref(system_bus);
else {
@@ -5697,40 +5698,27 @@ static int run_container(
}
bool registered_system = false, registered_runtime = false;
if (arg_register) {
r = register_machine(
if (arg_register != 0) {
r = register_machine_with_fallback_and_log(
arg_privileged ? RUNTIME_SCOPE_SYSTEM : _RUNTIME_SCOPE_INVALID,
system_bus,
runtime_bus,
arg_machine,
arg_uuid,
arg_container_service_name,
"container",
pid,
arg_directory,
arg_uuid,
/* cid= */ 0,
ifi,
arg_container_service_name);
if (r < 0) {
if (arg_privileged) /* if privileged the request to register definitely failed */
return r;
log_notice_errno(r, "Failed to register machine in system context, will try in user context.");
} else
registered_system = true;
if (!arg_privileged) {
r = register_machine(
runtime_bus,
arg_machine,
pid,
arg_directory,
arg_uuid,
ifi,
arg_container_service_name);
if (r < 0) {
if (!registered_system) /* neither registration worked: fail */
return r;
log_notice_errno(r, "Failed to register machine in user context, but succeeded in system context, will proceed.");
} else
registered_runtime = true;
}
/* address= */ NULL,
/* key_path= */ NULL,
/* allocate_unit= */ false,
/* graceful= */ arg_register < 0,
&registered_system,
&registered_runtime);
if (r < 0)
return r;
}
if (arg_keep_unit && (arg_slice || arg_property))
@@ -5942,10 +5930,7 @@ static int run_container(
r = wait_for_container(pid, &container_status);
/* Tell machined that we are gone. */
if (registered_system)
(void) unregister_machine(system_bus, arg_machine);
if (registered_runtime)
(void) unregister_machine(runtime_bus, arg_machine);
(void) unregister_machine_with_fallback_and_log(system_bus, runtime_bus, arg_machine, registered_system, registered_runtime);
if (r < 0)
/* We failed to wait for the container, or the container exited abnormally. */
+393
View File
@@ -0,0 +1,393 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "sd-bus.h"
#include "sd-id128.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-util.h"
#include "errno-util.h"
#include "json-util.h"
#include "log.h"
#include "machine-register.h"
#include "path-lookup.h"
#include "pidref.h"
#include "runtime-scope.h"
#include "socket-util.h"
#include "string-util.h"
#include "terminal-util.h"
static int register_machine_dbus_ex(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
int local_ifindex,
sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
int r;
assert(bus);
assert(machine_name);
assert(service);
assert(class);
r = bus_message_new_method_call(bus, &m, bus_machine_mgr, "RegisterMachineEx");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", machine_name);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"(sv)(sv)(sv)",
"Id", "ay", SD_BUS_MESSAGE_APPEND_ID128(uuid),
"Service", "s", service,
"Class", "s", class);
if (r < 0)
return bus_log_create_error(r);
if (pidref_is_set(pidref)) {
if (pidref->fd >= 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFD", "h", pidref->fd);
if (r < 0)
return bus_log_create_error(r);
}
if (pidref->fd_id > 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFDID", "t", pidref->fd_id);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "(sv)", "LeaderPID", "u", pidref->pid);
if (r < 0)
return bus_log_create_error(r);
}
}
if (!isempty(directory)) {
r = sd_bus_message_append(m, "(sv)", "RootDirectory", "s", directory);
if (r < 0)
return bus_log_create_error(r);
}
if (local_ifindex > 0) {
r = sd_bus_message_append(m, "(sv)", "NetworkInterfaces", "ai", 1, local_ifindex);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
return sd_bus_call(bus, m, 0, error, NULL);
}
static int register_machine_dbus(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
int local_ifindex) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
assert(machine_name);
assert(service);
assert(class);
/* First try RegisterMachineEx which supports PIDFD-based leader tracking. */
r = register_machine_dbus_ex(bus, machine_name, uuid, service, class, pidref, directory, local_ifindex, &error);
if (r >= 0)
return 0;
if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
return log_debug_errno(r, "Failed to register machine via D-Bus: %s", bus_error_message(&error, r));
sd_bus_error_free(&error);
r = bus_call_method(
bus,
bus_machine_mgr,
"RegisterMachineWithNetwork",
&error,
NULL,
"sayssusai",
machine_name,
SD_BUS_MESSAGE_APPEND_ID128(uuid),
service,
class,
pidref_is_set(pidref) ? (uint32_t) pidref->pid : 0,
strempty(directory),
local_ifindex > 0 ? 1 : 0, local_ifindex);
if (r < 0)
return log_debug_errno(r, "Failed to register machine via D-Bus: %s", bus_error_message(&error, r));
return 0;
}
int register_machine(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
unsigned cid,
int local_ifindex,
const char *address,
const char *key_path,
bool allocate_unit,
RuntimeScope scope) {
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
int r;
assert(machine_name);
assert(service);
assert(class);
/* First try to use varlink, as it provides more features (such as SSH support). */
_cleanup_free_ char *p = NULL;
r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
if (r >= 0)
r = sd_varlink_connect_address(&vl, p);
if (r == -ENOENT || ERRNO_IS_DISCONNECT(r)) {
log_debug_errno(r, "Failed to connect to machined via varlink%s%s, falling back to D-Bus: %m",
p ? " on " : "", strempty(p));
/* In case we are running with an older machined, fall back to D-Bus. */
if (!bus)
return log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Varlink connection to machined not available and no bus provided.");
return register_machine_dbus(bus, machine_name, uuid, service, class, pidref, directory, local_ifindex);
}
if (r < 0)
return log_debug_errno(r, "Failed to connect to machined on %s: %m", strna(p));
_cleanup_(sd_json_variant_unrefp) sd_json_variant *reply = NULL;
const char *error_id = NULL;
r = sd_varlink_callbo(
vl,
"io.systemd.Machine.Register",
&reply,
&error_id,
SD_JSON_BUILD_PAIR_STRING("name", machine_name),
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(uuid), "id", SD_JSON_BUILD_ID128(uuid)),
SD_JSON_BUILD_PAIR_STRING("service", service),
SD_JSON_BUILD_PAIR_STRING("class", class),
SD_JSON_BUILD_PAIR_CONDITION(VSOCK_CID_IS_REGULAR(cid), "vSockCid", SD_JSON_BUILD_UNSIGNED(cid)),
SD_JSON_BUILD_PAIR_CONDITION(local_ifindex > 0, "ifIndices", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_INTEGER(local_ifindex))),
SD_JSON_BUILD_PAIR_CONDITION(!!directory, "rootDirectory", SD_JSON_BUILD_STRING(directory)),
SD_JSON_BUILD_PAIR_CONDITION(!!address, "sshAddress", SD_JSON_BUILD_STRING(address)),
SD_JSON_BUILD_PAIR_CONDITION(!!key_path, "sshPrivateKeyPath", SD_JSON_BUILD_STRING(key_path)),
SD_JSON_BUILD_PAIR_CONDITION(isatty_safe(STDIN_FILENO), "allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(true)),
SD_JSON_BUILD_PAIR_CONDITION(allocate_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)),
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(pidref), "leaderProcessId", JSON_BUILD_PIDREF(pidref)));
if (r < 0)
return log_debug_errno(r, "Failed to register machine via varlink: %m");
if (error_id)
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply),
"Failed to register machine via varlink: %s", error_id);
return 0;
}
static const char* machine_registration_scope_string(RuntimeScope scope, bool registered_system, bool registered_user) {
if (scope == _RUNTIME_SCOPE_INVALID) {
if (!registered_system && !registered_user)
return "system and user";
if (!registered_system)
return "system";
return "user";
}
return runtime_scope_to_string(scope);
}
int register_machine_with_fallback_and_log(
RuntimeScope scope,
sd_bus *system_bus,
sd_bus *user_bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
unsigned cid,
int local_ifindex,
const char *address,
const char *key_path,
bool allocate_unit,
bool graceful,
bool *reterr_registered_system,
bool *reterr_registered_user) {
bool registered_system = false, registered_user = false;
int r = 0;
assert(IN_SET(scope, RUNTIME_SCOPE_SYSTEM, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID));
assert(system_bus || !IN_SET(scope, RUNTIME_SCOPE_SYSTEM, _RUNTIME_SCOPE_INVALID));
assert(user_bus || !IN_SET(scope, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID));
assert(machine_name);
assert(service);
assert(class);
assert(reterr_registered_system);
assert(reterr_registered_user);
if (IN_SET(scope, RUNTIME_SCOPE_SYSTEM, _RUNTIME_SCOPE_INVALID)) {
int q = register_machine(
system_bus,
machine_name,
uuid,
service,
class,
pidref,
directory,
cid,
local_ifindex,
address,
key_path,
scope == RUNTIME_SCOPE_SYSTEM ? allocate_unit : false,
RUNTIME_SCOPE_SYSTEM);
if (q < 0)
RET_GATHER(r, q);
else
registered_system = true;
}
if (IN_SET(scope, RUNTIME_SCOPE_USER, _RUNTIME_SCOPE_INVALID)) {
int q = register_machine(
user_bus,
machine_name,
uuid,
service,
class,
pidref,
directory,
cid,
local_ifindex,
address,
key_path,
allocate_unit,
RUNTIME_SCOPE_USER);
if (q < 0)
RET_GATHER(r, q);
else
registered_user = true;
}
if (r < 0) {
if (graceful) {
log_notice_errno(r, "Failed to register machine in %s context, ignoring: %m",
machine_registration_scope_string(scope, registered_system, registered_user));
r = 0;
} else
r = log_error_errno(r, "Failed to register machine in %s context: %m",
machine_registration_scope_string(scope, registered_system, registered_user));
}
if (reterr_registered_system)
*reterr_registered_system = registered_system;
if (reterr_registered_user)
*reterr_registered_user = registered_user;
return r;
}
int unregister_machine_with_fallback_and_log(
sd_bus *system_bus,
sd_bus *user_bus,
const char *machine_name,
bool registered_system,
bool registered_user) {
int r = 0;
bool failed_system = false, failed_user = false;
if (registered_system) {
int q = unregister_machine(system_bus, machine_name, RUNTIME_SCOPE_SYSTEM);
if (q < 0) {
RET_GATHER(r, q);
failed_system = true;
}
}
if (registered_user) {
int q = unregister_machine(user_bus, machine_name, RUNTIME_SCOPE_USER);
if (q < 0) {
RET_GATHER(r, q);
failed_user = true;
}
}
if (r < 0)
log_notice_errno(r, "Failed to unregister machine in %s context, ignoring: %m",
machine_registration_scope_string(
registered_system && registered_user ? _RUNTIME_SCOPE_INVALID :
registered_system ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
!failed_system, !failed_user));
return 0;
}
int unregister_machine(sd_bus *bus, const char *machine_name, RuntimeScope scope) {
int r;
assert(machine_name);
/* First try varlink */
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
_cleanup_free_ char *p = NULL;
r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
if (r >= 0)
r = sd_varlink_connect_address(&vl, p);
if (r >= 0) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *reply = NULL;
const char *error_id = NULL;
r = sd_varlink_callbo(
vl,
"io.systemd.Machine.Unregister",
&reply,
&error_id,
SD_JSON_BUILD_PAIR_STRING("name", machine_name));
if (r >= 0 && !error_id)
return 0;
if (r >= 0)
r = sd_varlink_error_to_errno(error_id, reply);
}
log_debug_errno(r, "Failed to unregister machine via varlink, falling back to D-Bus: %m");
/* Fall back to D-Bus */
if (!bus)
return log_debug_errno(SYNTHETIC_ERRNO(ESRCH), "Varlink connection to machined not available and no bus provided.");
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
if (r < 0)
return log_debug_errno(r, "Failed to unregister machine via D-Bus: %s", bus_error_message(&error, r));
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
int register_machine(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
unsigned cid,
int local_ifindex,
const char *address,
const char *key_path,
bool allocate_unit,
RuntimeScope scope);
int register_machine_with_fallback_and_log(
RuntimeScope scope,
sd_bus *system_bus,
sd_bus *user_bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const char *class,
const PidRef *pidref,
const char *directory,
unsigned cid,
int local_ifindex,
const char *address,
const char *key_path,
bool allocate_unit,
bool graceful,
bool *reterr_registered_system,
bool *reterr_registered_user);
int unregister_machine(sd_bus *bus, const char *machine_name, RuntimeScope scope);
int unregister_machine_with_fallback_and_log(
sd_bus *system_bus,
sd_bus *user_bus,
const char *machine_name,
bool registered_system,
bool registered_user);
+1
View File
@@ -125,6 +125,7 @@ shared_sources = files(
'machine-bind-user.c',
'machine-credential.c',
'machine-id-setup.c',
'machine-register.c',
'macvlan-util.c',
'main-func.c',
'metrics.c',
-1
View File
@@ -10,7 +10,6 @@ vmspawn_sources = files(
'vmspawn-settings.c',
'vmspawn-scope.c',
'vmspawn-mount.c',
'vmspawn-register.c',
)
vmspawn_extract_sources = files(
'vmspawn-util.c',
-104
View File
@@ -1,104 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "sd-bus.h"
#include "sd-id128.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "errno-util.h"
#include "json-util.h"
#include "log.h"
#include "path-lookup.h"
#include "pidref.h"
#include "socket-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "varlink-util.h"
#include "vmspawn-register.h"
int register_machine(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const PidRef *pidref,
const char *directory,
unsigned cid,
const char *address,
const char *key_path,
bool allocate_unit,
RuntimeScope scope) {
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
int r;
assert(machine_name);
assert(service);
/* First try to use varlink, as it provides more features (such as SSH support). */
_cleanup_free_ char *p = NULL;
r = runtime_directory_generic(scope, "systemd/machine/io.systemd.Machine", &p);
if (r < 0)
return r;
r = sd_varlink_connect_address(&vl, p);
if (r == -ENOENT || ERRNO_IS_DISCONNECT(r)) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
assert(bus);
/* In case we are running with an older machined, fallback to the existing D-Bus method. */
r = bus_call_method(
bus,
bus_machine_mgr,
"RegisterMachine",
&error,
NULL,
"sayssus",
machine_name,
SD_BUS_MESSAGE_APPEND_ID128(uuid),
service,
"vm",
(uint32_t) (pidref_is_set(pidref) ? pidref->pid : 0),
strempty(directory));
if (r < 0)
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to connect to machined on %p: %m", p);
return varlink_callbo_and_log(
vl,
"io.systemd.Machine.Register",
/* ret_reply= */ NULL,
SD_JSON_BUILD_PAIR_STRING("name", machine_name),
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(uuid), "id", SD_JSON_BUILD_ID128(uuid)),
SD_JSON_BUILD_PAIR_STRING("service", service),
SD_JSON_BUILD_PAIR_STRING("class", "vm"),
SD_JSON_BUILD_PAIR_CONDITION(VSOCK_CID_IS_REGULAR(cid), "vSockCid", SD_JSON_BUILD_UNSIGNED(cid)),
SD_JSON_BUILD_PAIR_CONDITION(!!directory, "rootDirectory", SD_JSON_BUILD_STRING(directory)),
SD_JSON_BUILD_PAIR_CONDITION(!!address, "sshAddress", SD_JSON_BUILD_STRING(address)),
SD_JSON_BUILD_PAIR_CONDITION(!!key_path, "sshPrivateKeyPath", SD_JSON_BUILD_STRING(key_path)),
SD_JSON_BUILD_PAIR_CONDITION(isatty_safe(STDIN_FILENO), "allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(true)),
SD_JSON_BUILD_PAIR_CONDITION(allocate_unit, "allocateUnit", SD_JSON_BUILD_BOOLEAN(true)),
SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(pidref), "leaderProcessId", JSON_BUILD_PIDREF(pidref)));
}
int unregister_machine(sd_bus *bus, const char *machine_name) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
r = bus_call_method(bus, bus_machine_mgr, "UnregisterMachine", &error, NULL, "s", machine_name);
if (r < 0)
log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
return 0;
}
-19
View File
@@ -1,19 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "shared-forward.h"
int register_machine(
sd_bus *bus,
const char *machine_name,
sd_id128_t uuid,
const char *service,
const PidRef *pidref,
const char *directory,
unsigned cid,
const char *address,
const char *key_path,
bool allocate_unit,
RuntimeScope scope);
int unregister_machine(sd_bus *bus, const char *machine_name);
+18 -43
View File
@@ -51,6 +51,7 @@
#include "log.h"
#include "machine-bind-user.h"
#include "machine-credential.h"
#include "machine-register.h"
#include "main-func.h"
#include "mkdir.h"
#include "namespace-util.h"
@@ -89,7 +90,6 @@
#include "utf8.h"
#include "vmspawn-mount.h"
#include "vmspawn-qemu-config.h"
#include "vmspawn-register.h"
#include "vmspawn-scope.h"
#include "vmspawn-settings.h"
#include "vmspawn-util.h"
@@ -150,7 +150,7 @@ static bool arg_firmware_describe = false;
static Set *arg_firmware_features_include = NULL;
static Set *arg_firmware_features_exclude = NULL;
static char *arg_forward_journal = NULL;
static bool arg_register = true;
static int arg_register = -1;
static bool arg_keep_unit = false;
static sd_id128_t arg_uuid = {};
static char **arg_kernel_cmdline_extra = NULL;
@@ -665,7 +665,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_REGISTER:
r = parse_boolean_argument("--register=", optarg, &arg_register);
r = parse_tristate_argument_with_auto("--register=", optarg, &arg_register);
if (r < 0)
return r;
@@ -2234,7 +2234,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
/* Registration always happens on the system bus */
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL;
if (arg_register || arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
if (arg_register != 0 || arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
r = sd_bus_default_system(&system_bus);
if (r < 0)
return log_error_errno(r, "Failed to open system bus: %m");
@@ -3571,7 +3571,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
}
bool scope_allocated = false;
if (!arg_keep_unit && (!arg_register || arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)) {
if (!arg_keep_unit && (arg_register == 0 || arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)) {
r = allocate_scope(
runtime_bus,
arg_machine,
@@ -3596,51 +3596,29 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
}
bool registered_system = false, registered_runtime = false;
if (arg_register) {
if (arg_register != 0) {
char vm_address[STRLEN("vsock/") + DECIMAL_STR_MAX(unsigned)];
xsprintf(vm_address, "vsock/%u", child_cid);
r = register_machine(
r = register_machine_with_fallback_and_log(
arg_runtime_scope == RUNTIME_SCOPE_USER ? _RUNTIME_SCOPE_INVALID : RUNTIME_SCOPE_SYSTEM,
system_bus,
runtime_bus,
arg_machine,
arg_uuid,
"systemd-vmspawn",
"vm",
&child_pidref,
arg_directory,
child_cid,
/* local_ifindex= */ 0,
child_cid != VMADDR_CID_ANY ? vm_address : NULL,
ssh_private_key_path,
!arg_keep_unit && arg_runtime_scope == RUNTIME_SCOPE_SYSTEM,
RUNTIME_SCOPE_SYSTEM);
if (r < 0) {
/* if privileged the request to register definitely failed */
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM)
return r;
log_notice_errno(r, "Failed to register machine in system context, will try in user context.");
} else
registered_system = true;
if (arg_runtime_scope == RUNTIME_SCOPE_USER) {
r = register_machine(
runtime_bus,
arg_machine,
arg_uuid,
"systemd-vmspawn",
&child_pidref,
arg_directory,
child_cid,
child_cid != VMADDR_CID_ANY ? vm_address : NULL,
ssh_private_key_path,
!arg_keep_unit,
RUNTIME_SCOPE_USER);
if (r < 0) {
if (!registered_system) /* neither registration worked: fail */
return r;
log_notice_errno(r, "Failed to register machine in user context, but succeeded in system context, will proceed.");
} else
registered_runtime = true;
}
!arg_keep_unit,
/* graceful= */ arg_register < 0,
&registered_system,
&registered_runtime);
if (r < 0)
return r;
}
/* Report that the VM is now set up */
@@ -3743,10 +3721,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
if (scope_allocated)
terminate_scope(runtime_bus, arg_machine);
if (registered_system)
(void) unregister_machine(system_bus, arg_machine);
if (registered_runtime)
(void) unregister_machine(runtime_bus, arg_machine);
(void) unregister_machine_with_fallback_and_log(system_bus, runtime_bus, arg_machine, registered_system, registered_runtime);
if (use_vsock) {
if (exit_status == INT_MAX) {