From: Luca Boccassi Date: Tue, 16 Sep 2025 13:45:58 +0000 (+0100) Subject: machined: add PIDFD D-Bus variants for registering/creating machines X-Git-Tag: v259-rc1~455 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d80af3b97b94e450a002ddac13874a953f0eab3e;p=thirdparty%2Fsystemd.git machined: add PIDFD D-Bus variants for registering/creating machines Current methods take a numeric PID, but we know that is unreliable for the usual reasons. Add variants that take a PIDFD instead, or a PID + PIDFDID combination for remote users. --- diff --git a/man/org.freedesktop.machine1.xml b/man/org.freedesktop.machine1.xml index fcabd6da2b3..39bd96d87c5 100644 --- a/man/org.freedesktop.machine1.xml +++ b/man/org.freedesktop.machine1.xml @@ -63,6 +63,10 @@ node /org/freedesktop/machine1 { in ai ifindices, in a(sv) scope_properties, out o path); + CreateMachineEx(in s name, + in a(sv) properties, + in a(sv) scope_properties, + out o path); RegisterMachine(in s name, in ay id, in s service, @@ -78,6 +82,9 @@ node /org/freedesktop/machine1 { in s root_directory, in ai ifindices, out o path); + RegisterMachineEx(in s name, + in a(sv) properties, + out o path); UnregisterMachine(in s name); TerminateMachine(in s id); KillMachine(in s name, @@ -216,10 +223,14 @@ node /org/freedesktop/machine1 { + + + + @@ -353,6 +364,31 @@ node /org/freedesktop/machine1 { multiple times, one instance for each container/VM they manage, and are invoked as system services. + RegisterMachineEx() and CreateMachineEx() are similar + to the counterparts, but take a series of key/value pairs instead of a fixed number of parameters, to + allow for future extensions, and take a PIDFD instead of a PID for the leader parameter. The currently + supported parameters are: + + Id (ay): the machine UUID. + Service (s): the service string. + Class (s): the class string. + LeaderPIDFD (h): A PIDFD for the leader process of the machine. + This parameter is optional. If it is specified, it is preferred over the combination of + LeaderPID + and LeaderPIDFDID. + LeaderPID (u): A PID for the leader process of the + machine. This parameter is optional. Must be specified together with + LeaderPIDFDID. + LeaderPIDFDID (t): A PIDFDID for the leader + process of the machine. This parameter is optional. Must be specified together with + LeaderPID. + RootDirectory (s): The root directory of the container. This + parameter is optional and for informational purposes only. + NetworkInterfaces (ai): An array of network + interface indices, as in + CreateMachineWithNetwork(). This parameter is optional. + + CreateMachineWithNetwork() and RegisterMachineWithNetwork() are similar to CreateMachine() and RegisterMachine() but take an extra argument: an array of network interface @@ -753,6 +789,8 @@ $ gdbus introspect --system \ LeaderPIDFDId, Supervisor, SupervisorPIDFDId, Subgroup, and UID were added in version 258. + CreateMachineEx(), and RegisterMachineEx() were added + in version 259. diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 91e5e218698..7d2e3dfb62c 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -33,6 +33,7 @@ #include "operation.h" #include "os-util.h" #include "path-util.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "unit-def.h" @@ -226,11 +227,140 @@ static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_ return sd_bus_message_send(reply); } +static int machine_add_from_params( + Manager *manager, + sd_bus_message *message, + const char *polkit_action, + const char *name, + MachineClass c, + sd_id128_t id, + const char *service, + PidRef *leader_pidref, + PidRef *supervisor_pidref, + const char *root_directory, + const int32_t *netif, + size_t n_netif, + unsigned cid, + const char *ssh_address, + const char *ssh_private_key_path, + Machine **ret, + sd_bus_error *error) { + + Machine *m; + int r; + + assert(manager); + assert(message); + assert(name); + assert(ret); + + if (leader_pidref->pid == 1) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); + if (supervisor_pidref->pid == 1) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supervisor PID"); + + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + uid_t uid; + r = sd_bus_creds_get_euid(creds, &uid); + if (r < 0) + return r; + + /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */ + if (uid != 0) { + r = process_is_owned_by_uid(leader_pidref, uid); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users"); + } + + const char *details[] = { + "name", name, + "class", machine_class_to_string(c), + NULL + }; + + r = bus_verify_polkit_async( + message, + polkit_action, + details, + &manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 0; /* Will call us back */ + + r = manager_add_machine(manager, name, &m); + if (r < 0) + return r; + + m->leader = TAKE_PIDREF(*leader_pidref); + m->supervisor = TAKE_PIDREF(*supervisor_pidref); + m->class = c; + m->id = id; + m->uid = uid; + m->vsock_cid = cid; + + if (!isempty(service)) { + m->service = strdup(service); + if (!m->service) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(root_directory)) { + m->root_directory = strdup(root_directory); + if (!m->root_directory) { + r = -ENOMEM; + goto fail; + } + } + + if (n_netif > 0) { + assert_cc(sizeof(int32_t) == sizeof(int)); + m->netif = memdup(netif, sizeof(int32_t) * n_netif); + if (!m->netif) { + r = -ENOMEM; + goto fail; + } + + m->n_netif = n_netif; + } + + if (!isempty(ssh_address)) { + m->ssh_address = strdup(ssh_address); + if (!m->ssh_address) { + r = -ENOMEM; + goto fail; + } + } + + if (!isempty(ssh_private_key_path)) { + m->ssh_private_key_path = strdup(ssh_private_key_path); + if (!m->ssh_private_key_path) { + r = -ENOMEM; + goto fail; + } + } + + *ret = m; + return 1; + +fail: + machine_add_to_gc_queue(m); + return r; +} + static int method_create_or_register_machine( Manager *manager, sd_bus_message *message, const char *polkit_action, - bool read_network, Machine **ret, sd_bus_error *error) { @@ -240,7 +370,6 @@ static int method_create_or_register_machine( MachineClass c; uint32_t leader; sd_id128_t id; - Machine *m; size_t n_netif = 0; int r; @@ -262,7 +391,7 @@ static int method_create_or_register_machine( if (r < 0) return r; - if (read_network) { + if (endswith(sd_bus_message_get_member(message), "WithNetwork")) { r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif); if (r < 0) return r; @@ -312,95 +441,224 @@ static int method_create_or_register_machine( if (hashmap_get(manager->machines, name)) return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); - _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + return machine_add_from_params( + manager, + message, + polkit_action, + name, + c, + id, + service, + &leader_pidref, + &supervisor_pidref, + root_directory, + netif, + n_netif, + /* cid= */ 0, + /* ssh_address= */ NULL, + /* ssh_private_key_path= */ NULL, + ret, + error); +} + +static int method_create_or_register_machine_ex( + Manager *manager, + sd_bus_message *message, + const char *polkit_action, + Machine **ret, + sd_bus_error *error) { + + const char *name = NULL, *service = NULL, *class = NULL, *root_directory = NULL, *ssh_address = NULL, *ssh_private_key_path = NULL; + _cleanup_(pidref_done) PidRef leader_pidref = PIDREF_NULL, supervisor_pidref = PIDREF_NULL; + sd_id128_t id = SD_ID128_NULL; + const int32_t *netif = NULL; + size_t n_netif = 0; + unsigned cid = 0; + MachineClass c; + uint64_t leader_pidfdid = 0; + uint32_t leader_pid = 0; + int r, leader_pidfd = -EBADF; + + assert(manager); + assert(message); + assert(ret); + + r = sd_bus_message_read(message, "s", &name); if (r < 0) return r; + if (!hostname_is_valid(name, 0)) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name"); - uid_t uid; - r = sd_bus_creds_get_euid(creds, &uid); + r = sd_bus_message_enter_container(message, 'a', "(sv)"); if (r < 0) return r; - /* Ensure an unprivileged user cannot claim any process they don't control as their own machine */ - if (uid != 0) { - r = process_is_owned_by_uid(&leader_pidref, uid); + for (;;) { + const char *key; + + r = sd_bus_message_enter_container(message, 'r', "sv"); if (r < 0) return r; if (r == 0) - return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users"); - } + break; - const char *details[] = { - "name", name, - "class", machine_class_to_string(c), - NULL - }; + r = sd_bus_message_read(message, "s", &key); + if (r < 0) + return r; - r = bus_verify_polkit_async( - message, - polkit_action, - details, - &manager->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 0; /* Will call us back */ + r = sd_bus_message_enter_container(message, 'v', NULL); + if (r < 0) + return r; - r = manager_add_machine(manager, name, &m); + if (streq(key, "Id")) { + r = bus_message_read_id128(message, &id); + if (r < 0) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter"); + } else if (streq(key, "Service")) { + r = sd_bus_message_read(message, "s", &service); + if (r < 0) + return r; + } else if (streq(key, "Class")) { + r = sd_bus_message_read(message, "s", &class); + if (r < 0) + return r; + } else if (streq(key, "LeaderPID")) { + r = sd_bus_message_read(message, "u", &leader_pid); + if (r < 0) + return r; + } else if (streq(key, "LeaderPIDFD")) { + r = sd_bus_message_read(message, "h", &leader_pidfd); + if (r < 0) + return r; + } else if (streq(key, "LeaderPIDFDID")) { + r = sd_bus_message_read(message, "t", &leader_pidfdid); + if (r < 0) + return r; + } else if (streq(key, "RootDirectory")) { + r = sd_bus_message_read(message, "s", &root_directory); + if (r < 0) + return r; + } else if (streq(key, "NetworkInterfaces")) { + r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif); + if (r < 0) + return r; + + n_netif /= sizeof(int32_t); + + for (size_t i = 0; i < n_netif; i++) + if (netif[i] <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]); + } else if (streq(key, "VSockCID")) { + r = sd_bus_message_read(message, "u", &cid); + if (r < 0) + return r; + + if (!VSOCK_CID_IS_REGULAR(cid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "JSON field 'vSockCid' is not a regular VSOCK CID."); + } else if (streq(key, "SSHAddress")) { + r = sd_bus_message_read(message, "s", &ssh_address); + if (r < 0) + return r; + } else if (streq(key, "SSHPrivateKeyPath")) { + r = sd_bus_message_read(message, "s", &ssh_private_key_path); + if (r < 0) + return r; + } else + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown property '%s'", key); + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(message); if (r < 0) return r; - m->leader = TAKE_PIDREF(leader_pidref); - m->supervisor = TAKE_PIDREF(supervisor_pidref); - m->class = c; - m->id = id; - m->uid = uid; - - if (!isempty(service)) { - m->service = strdup(service); - if (!m->service) { - r = -ENOMEM; - goto fail; - } + if (isempty(class)) + c = _MACHINE_CLASS_INVALID; + else { + c = machine_class_from_string(class); + if (c < 0) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter"); } - if (!isempty(root_directory)) { - m->root_directory = strdup(root_directory); - if (!m->root_directory) { - r = -ENOMEM; - goto fail; - } - } + if (!isempty(root_directory) && (!path_is_absolute(root_directory) || !path_is_valid(root_directory))) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path"); - if (n_netif > 0) { - assert_cc(sizeof(int32_t) == sizeof(int)); - m->netif = memdup(netif, sizeof(int32_t) * n_netif); - if (!m->netif) { - r = -ENOMEM; - goto fail; + if (hashmap_get(manager->machines, name)) + return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); + + /* If a PID is specified that's the leader, but if the client process is different from it, than that's the supervisor */ + if (leader_pidfd >= 0) { + r = pidref_set_pidfd(&leader_pidref, leader_pidfd); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to parse PIDFD %d: %m", leader_pidfd); + + if (leader_pid > 0 && leader_pidref.pid != (pid_t) leader_pid) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPID and LeaderPIDFD refer to different processes"); + if (leader_pidfdid > 0) { + r = pidref_acquire_pidfd_id(&leader_pidref); + if (r >= 0 && leader_pidref.fd_id != leader_pidfdid) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPIDFDID does not match the inode number of LeaderPIDFD"); } + } else if (leader_pid > 0 && leader_pidfdid > 0) { + r = pidref_set_pid_and_pidfd_id(&leader_pidref, leader_pid, leader_pidfdid); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to pin process " PID_FMT " by PIDFDID %" PRIu64 ": %m", (pid_t) leader_pid, leader_pidfdid); + } else if (leader_pid > 0 || leader_pidfdid > 0) + return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Both LeaderPID and LeaderPIDFDID must be specified to identify the leader process by PIDFDID"); - m->n_netif = n_netif; - } + if (pidref_is_set(&leader_pidref)) { + _cleanup_(pidref_done) PidRef client_pidref = PIDREF_NULL; + r = bus_query_sender_pidref(message, &client_pidref); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m"); - *ret = m; - return 1; + if (!pidref_equal(&client_pidref, &leader_pidref)) + supervisor_pidref = TAKE_PIDREF(client_pidref); + } else { + /* If no PID is specified, the client is the leader */ + r = bus_query_sender_pidref(message, &leader_pidref); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m"); + } -fail: - machine_add_to_gc_queue(m); - return r; + return machine_add_from_params( + manager, + message, + polkit_action, + name, + c, + id, + service, + &leader_pidref, + &supervisor_pidref, + root_directory, + netif, + n_netif, + cid, + ssh_address, + ssh_private_key_path, + ret, + error); } -static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) { +static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *manager = ASSERT_PTR(userdata); Machine *m = NULL; int r; assert(message); - r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", read_network, &m, error); + if (sd_bus_message_is_method_call(message, NULL, "CreateMachineEx")) + r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.create-machines", &m, error); + else + r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", &m, error); if (r < 0) return r; if (r == 0) @@ -422,15 +680,7 @@ fail: return r; } -static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_create_machine_internal(message, true, userdata, error); -} - -static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_create_machine_internal(message, false, userdata, error); -} - -static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) { +static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *manager = ASSERT_PTR(userdata); _cleanup_free_ char *p = NULL; Machine *m = NULL; @@ -438,7 +688,10 @@ static int method_register_machine_internal(sd_bus_message *message, bool read_n assert(message); - r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", read_network, &m, error); + if (sd_bus_message_is_method_call(message, NULL, "RegisterMachineEx")) + r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.register-machine", &m, error); + else + r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", &m, error); if (r < 0) return r; if (r == 0) @@ -482,14 +735,6 @@ fail: return r; } -static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_register_machine_internal(message, true, userdata, error); -} - -static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) { - return method_register_machine_internal(message, false, userdata, error); -} - static int redirect_method_to_machine(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) { Machine *machine; const char *name; @@ -969,7 +1214,12 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork", SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties), SD_BUS_RESULT("o", path), - method_create_machine_with_network, + method_create_machine, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("CreateMachineEx", + SD_BUS_ARGS("s", name, "a(sv)", properties, "a(sv)", scope_properties), + SD_BUS_RESULT("o", path), + method_create_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("RegisterMachine", SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory), @@ -979,7 +1229,12 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork", SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices), SD_BUS_RESULT("o", path), - method_register_machine_with_network, + method_register_machine, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RegisterMachineEx", + SD_BUS_ARGS("s", name, "a(sv)", properties), + SD_BUS_RESULT("o", path), + method_register_machine, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_ARGS("UnregisterMachine", SD_BUS_ARGS("s", name), diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf index 50772946929..69fa2d20a70 100644 --- a/src/machine/org.freedesktop.machine1.conf +++ b/src/machine/org.freedesktop.machine1.conf @@ -190,6 +190,10 @@ send_interface="org.freedesktop.machine1.Manager" send_member="CreateMachineWithNetwork"/> + + @@ -198,6 +202,10 @@ send_interface="org.freedesktop.machine1.Manager" send_member="RegisterMachineWithNetwork"/> + + = 0; } +static int create_or_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 *slice, + CustomMount *mounts, + unsigned n_mounts, + int kill_signal, + char **properties, + sd_bus_message *properties_message, + const char *service, + StartMode start_mode, + sd_bus_error *error, + bool keep_unit) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + int r; + + assert(error); + + r = bus_message_new_method_call(bus, &m, bus_machine_mgr, keep_unit ? "RegisterMachineEx" : "CreateMachineEx"); + 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); + + if (!keep_unit) { + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) + return bus_log_create_error(r); + + if (!isempty(slice)) { + r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice); + if (r < 0) + return bus_log_create_error(r); + } + + r = append_controller_property(bus, m); + if (r < 0) + return r; + + r = append_machine_properties( + m, + mounts, + n_mounts, + kill_signal, + start_mode == START_BOOT && can_set_coredump_receive(bus) > 0); + if (r < 0) + return r; + + if (properties_message) { + r = sd_bus_message_copy(m, properties_message, true); + if (r < 0) + return bus_log_create_error(r); + } + + r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties); + if (r < 0) + return 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, @@ -153,6 +273,27 @@ int register_machine( assert(bus); + r = create_or_register_machine_ex( + bus, + machine_name, + pid, + directory, + uuid, + local_ifindex, + slice, + mounts, + n_mounts, + kill_signal, + properties, + properties_message, + service, + start_mode, + &error, + FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)); + 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)); if (FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)) { r = bus_call_method( bus,