int allocate_scope( sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *scope = NULL; const char *description, *object; int r; assert(bus); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch job: %m"); r = unit_name_mangle_with_suffix(machine_name, UNIT_NAME_NOGLOB, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "ss", scope, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); description = strjoina("Container ", machine_name); r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)", "PIDs", "au", 1, pid, "Description", "s", description, "Delegate", "b", 1, "Slice", "s", isempty(slice) ? "machine.slice" : 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, properties); if (r < 0) return r; r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties); if (r < 0) return r; r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); /* No auxiliary units */ r = sd_bus_message_append( m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to allocate scope: %s", bus_error_message(&error, r)); return r; } r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, false); if (r < 0) return r; return 0; }
static int start_transient_timer( sd_bus *bus, char **argv) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *timer = NULL, *service = NULL; const char *object = NULL; int r; assert(bus); assert(argv); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_oom(); if (arg_unit) { switch (unit_name_to_type(arg_unit)) { case UNIT_SERVICE: service = strdup(arg_unit); if (!service) return log_oom(); r = unit_name_change_suffix(service, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); break; case UNIT_TIMER: timer = strdup(arg_unit); if (!timer) return log_oom(); r = unit_name_change_suffix(timer, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); break; default: r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); break; } } else { r = make_unit_name(bus, UNIT_SERVICE, &service); if (r < 0) return r; r = unit_name_change_suffix(service, ".timer", &timer); if (r < 0) return log_error_errno(r, "Failed to change unit suffix: %m"); } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and Mode */ r = sd_bus_message_append(m, "ss", timer, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_timer_set_properties(m); 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); r = sd_bus_message_open_container(m, 'a', "(sa(sv))"); if (r < 0) return bus_log_create_error(r); if (!strv_isempty(argv)) { r = sd_bus_message_open_container(m, 'r', "sa(sv)"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_append(m, "s", service); 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 = transient_service_set_properties(m, argv, NULL); 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); r = sd_bus_message_close_container(m); 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); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r)); return r; } r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; if (!arg_quiet) { log_info("Running timer as unit: %s", timer); if (argv[0]) log_info("Will run service as unit: %s", service); } return 0; }
static int start_transient_service( sd_bus *bus, char **argv, int *retval) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *service = NULL, *pty_path = NULL; _cleanup_close_ int master = -1; int r; assert(bus); assert(argv); assert(retval); if (arg_pty) { if (arg_transport == BUS_TRANSPORT_LOCAL) { master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY); if (master < 0) return log_error_errno(errno, "Failed to acquire pseudo tty: %m"); r = ptsname_malloc(master, &pty_path); if (r < 0) return log_error_errno(r, "Failed to determine tty name: %m"); if (unlockpt(master) < 0) return log_error_errno(errno, "Failed to unlock tty: %m"); } else if (arg_transport == BUS_TRANSPORT_MACHINE) { _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL; const char *s; r = sd_bus_default_system(&system_bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_call_method(system_bus, "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "OpenMachinePTY", &error, &pty_reply, "s", arg_host); if (r < 0) { log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r)); return r; } r = sd_bus_message_read(pty_reply, "hs", &master, &s); if (r < 0) return bus_log_parse_error(r); master = fcntl(master, F_DUPFD_CLOEXEC, 3); if (master < 0) return log_error_errno(errno, "Failed to duplicate master fd: %m"); pty_path = strdup(s); if (!pty_path) return log_oom(); } else assert_not_reached("Can't allocate tty via ssh"); } if (!arg_no_block) { r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_error_errno(r, "Could not watch jobs: %m"); } if (arg_unit) { r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); } else { r = make_unit_name(bus, UNIT_SERVICE, &service); if (r < 0) return r; } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and mode */ r = sd_bus_message_append(m, "ss", service, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_service_set_properties(m, argv, pty_path); 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); /* Auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r)); if (w) { const char *object; r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; } if (!arg_quiet) log_info("Running as unit: %s", service); if (arg_wait || master >= 0) { _cleanup_(run_context_free) RunContext c = {}; c.bus = sd_bus_ref(bus); r = sd_event_default(&c.event); if (r < 0) return log_error_errno(r, "Failed to get event loop: %m"); if (master >= 0) { assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0); (void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL); (void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL); if (!arg_quiet) log_info("Press ^] three times within 1s to disconnect TTY."); r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); pty_forward_set_handler(c.forward, pty_forward_handler, &c); } if (arg_wait) { _cleanup_free_ char *path = NULL; const char *mt; path = unit_dbus_path_from_name(service); if (!path) return log_oom(); mt = strjoina("type='signal'," "sender='org.freedesktop.systemd1'," "path='", path, "'," "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'"); r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c); if (r < 0) return log_error_errno(r, "Failed to add properties changed signal."); r = sd_bus_attach_event(bus, c.event, 0); if (r < 0) return log_error_errno(r, "Failed to attach bus to event loop."); } r = sd_event_loop(c.event); if (r < 0) return log_error_errno(r, "Failed to run event loop: %m"); if (c.forward) { char last_char = 0; r = pty_forward_get_last_char(c.forward, &last_char); if (r >= 0 && !arg_quiet && last_char != '\n') fputc('\n', stdout); } if (!arg_quiet) { if (!isempty(c.result)) log_info("Finished with result: %s", strna(c.result)); if (c.exit_code == CLD_EXITED) log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status); else if (c.exit_code > 0) log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status)); if (c.inactive_enter_usec > 0 && c.inactive_enter_usec != USEC_INFINITY && c.inactive_exit_usec > 0 && c.inactive_exit_usec != USEC_INFINITY && c.inactive_enter_usec > c.inactive_exit_usec) { char ts[FORMAT_TIMESPAN_MAX]; log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC)); } if (c.cpu_usage_nsec > 0 && c.cpu_usage_nsec != NSEC_INFINITY) { char ts[FORMAT_TIMESPAN_MAX]; log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC)); } } /* Try to propagate the service's return value */ if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED) *retval = c.exit_status; else *retval = EXIT_FAILURE; } return 0; }
static int start_transient_scope( sd_bus *bus, char **argv) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_strv_free_ char **env = NULL, **user_env = NULL; _cleanup_free_ char *scope = NULL; const char *object = NULL; int r; assert(bus); assert(argv); r = bus_wait_for_jobs_new(bus, &w); if (r < 0) return log_oom(); if (arg_unit) { r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); } else { r = make_unit_name(bus, UNIT_SCOPE, &scope); if (r < 0) return r; } r = sd_bus_message_new_method_call( bus, &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartTransientUnit"); if (r < 0) return bus_log_create_error(r); r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password); if (r < 0) return bus_log_create_error(r); /* Name and Mode */ r = sd_bus_message_append(m, "ss", scope, "fail"); if (r < 0) return bus_log_create_error(r); /* Properties */ r = sd_bus_message_open_container(m, 'a', "(sv)"); if (r < 0) return bus_log_create_error(r); r = transient_scope_set_properties(m); 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); /* Auxiliary units */ r = sd_bus_message_append(m, "a(sa(sv))", 0); if (r < 0) return bus_log_create_error(r); polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) { log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r)); return r; } if (arg_nice_set) { if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0) return log_error_errno(errno, "Failed to set nice level: %m"); } if (arg_exec_group) { gid_t gid; r = get_group_creds(&arg_exec_group, &gid); if (r < 0) return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group); if (setresgid(gid, gid, gid) < 0) return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); } if (arg_exec_user) { const char *home, *shell; uid_t uid; gid_t gid; r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell); if (r < 0) return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user); r = strv_extendf(&user_env, "HOME=%s", home); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "SHELL=%s", shell); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "USER=%s", arg_exec_user); if (r < 0) return log_oom(); r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user); if (r < 0) return log_oom(); if (!arg_exec_group) { if (setresgid(gid, gid, gid) < 0) return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid); } if (setresuid(uid, uid, uid) < 0) return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid); } env = strv_env_merge(3, environ, user_env, arg_environment); if (!env) return log_oom(); r = sd_bus_message_read(reply, "o", &object); if (r < 0) return bus_log_parse_error(r); r = bus_wait_for_jobs_one(w, object, arg_quiet); if (r < 0) return r; if (!arg_quiet) log_info("Running scope as unit: %s", scope); execvpe(argv[0], argv, env); return log_error_errno(errno, "Failed to execute: %m"); }