<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>
<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>
comps=''
;;
--register)
- comps='yes no'
+ comps='yes no auto'
;;
--network-interface)
comps=$(__get_interfaces)
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'
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
'--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)' \
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,
#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;
#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"
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;
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;
/* 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");
_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 {
}
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,
+ ®istered_system,
+ ®istered_runtime);
+ if (r < 0)
+ return r;
}
if (arg_keep_unit && (arg_slice || arg_property))
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. */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
'machine-bind-user.c',
'machine-credential.c',
'machine-id-setup.c',
+ 'machine-register.c',
'macvlan-util.c',
'main-func.c',
'metrics.c',
'vmspawn-settings.c',
'vmspawn-scope.c',
'vmspawn-mount.c',
- 'vmspawn-register.c',
)
vmspawn_extract_sources = files(
'vmspawn-util.c',
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-/* 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);
#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"
#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"
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;
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;
/* 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");
}
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,
}
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,
+ ®istered_system,
+ ®istered_runtime);
+ if (r < 0)
+ return r;
}
/* Report that the VM is now set up */
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) {