Beispiel #1
0
static int write_requires_after(FILE *f, const char *opts) {
    _cleanup_strv_free_ char **names = NULL, **units = NULL;
    _cleanup_free_ char *res = NULL;
    char **s;
    int r;

    assert(f);
    assert(opts);

    r = fstab_extract_values(opts, "x-systemd.requires", &names);
    if (r < 0)
        return log_warning_errno(r, "Failed to parse options: %m");
    if (r == 0)
        return 0;

    STRV_FOREACH(s, names) {
        char *x;

        r = unit_name_mangle_with_suffix(*s, UNIT_NAME_NOGLOB, ".mount", &x);
        if (r < 0)
            return log_error_errno(r, "Failed to generate unit name: %m");
        r = strv_consume(&units, x);
        if (r < 0)
            return log_oom();
    }
Beispiel #2
0
int terminate_scope(
                sd_bus *bus,
                const char *machine_name) {

        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        _cleanup_free_ char *scope = NULL;
        int r;

        r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
        if (r < 0)
                return log_error_errno(r, "Failed to mangle scope name: %m");

        r = sd_bus_call_method(
                        bus,
                        "org.freedesktop.systemd1",
                        "/org/freedesktop/systemd1",
                        "org.freedesktop.systemd1.Manager",
                        "AbandonScope",
                        &error,
                        NULL,
                        "s",
                        scope);
        if (r < 0) {
                log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
                sd_bus_error_free(&error);
        }

        r = sd_bus_call_method(
                        bus,
                        "org.freedesktop.systemd1",
                        "/org/freedesktop/systemd1",
                        "org.freedesktop.systemd1.Manager",
                        "KillUnit",
                        &error,
                        NULL,
                        "ssi",
                        scope,
                        "all",
                        (int32_t) SIGKILL);
        if (r < 0) {
                log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
                sd_bus_error_free(&error);
        }

        r = sd_bus_call_method(
                        bus,
                        "org.freedesktop.systemd1",
                        "/org/freedesktop/systemd1",
                        "org.freedesktop.systemd1.Manager",
                        "UnrefUnit",
                        &error,
                        NULL,
                        "s",
                        scope);
        if (r < 0)
                log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));

        return 0;
}
Beispiel #3
0
static int transient_cgroup_set_properties(sd_bus_message *m) {
    int r;
    assert(m);

    if (!isempty(arg_slice)) {
        _cleanup_free_ char *slice;

        r = unit_name_mangle_with_suffix(arg_slice, UNIT_NAME_NOGLOB, ".slice", &slice);
        if (r < 0)
            return r;

        r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
        if (r < 0)
            return r;
    }

    return 0;
}
Beispiel #4
0
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;
}
Beispiel #5
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;
}
Beispiel #6
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;
}
Beispiel #7
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");
}