X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=599d5907478408e4910880c738dd6f86b0e65b01;hp=6e98c05152dfaaadc01920e18db5b79c82e5403e;hb=0c6ea3a4e2ac3f350dcb58e8f08bb74b030cd624;hpb=4723e4b2a4ca7a7df449ab2377770301cce6abf7 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 6e98c0515..599d59074 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -101,6 +101,7 @@ static bool arg_recursive = false; static int arg_force = 0; static bool arg_ask_password = true; static bool arg_runtime = false; +static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; static int arg_signal = SIGTERM; @@ -319,12 +320,6 @@ static int compare_unit_info(const void *a, const void *b) { static bool output_show_unit(const UnitInfo *u, char **patterns) { const char *dot; - if (!strv_isempty(arg_states)) - return - strv_contains(arg_states, u->load_state) || - strv_contains(arg_states, u->sub_state) || - strv_contains(arg_states, u->active_state); - if (!strv_isempty(patterns)) { char **pattern; @@ -461,7 +456,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { } if (circle_len > 0) - printf("%s%s%s", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle); + printf("%s%s%s ", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle); printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s", on_active, id_len, id, off_active, @@ -513,6 +508,7 @@ static int get_unit_list( int c, sd_bus_message **_reply) { + _cleanup_bus_message_unref_ sd_bus_message *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; size_t size = c; @@ -523,15 +519,22 @@ static int get_unit_list( assert(unit_infos); assert(_reply); - r = sd_bus_call_method( + r = sd_bus_message_new_method_call( bus, + &m, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - "ListUnits", - &error, - &reply, - NULL); + "ListUnitsFiltered"); + + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_strv(m, arg_states); + 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 list units: %s", bus_error_message(&error, r)); return r; @@ -1925,9 +1928,9 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha for (i = 0; i < n_changes; i++) { if (changes[i].type == UNIT_FILE_SYMLINK) - log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path); + log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source); else - log_info("rm '%s'", changes[i].path); + log_info("Removed symlink %s.", changes[i].path); } } @@ -1942,9 +1945,9 @@ static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) { while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { if (!arg_quiet) { if (streq(type, "symlink")) - log_info("ln -s '%s' '%s'", source, path); + log_info("Created symlink from %s to %s.", path, source); else - log_info("rm '%s'", path); + log_info("Removed symlink %s.", path); } } if (r < 0) @@ -3167,6 +3170,7 @@ typedef struct UnitStatusInfo { const char *status_text; const char *pid_file; bool running:1; + int status_errno; usec_t start_timestamp; usec_t exit_timestamp; @@ -3438,6 +3442,8 @@ static void print_status_info( if (i->status_text) printf(" Status: \"%s\"\n", i->status_text); + if (i->status_errno > 0) + printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno)); if (i->control_group && (i->main_pid > 0 || i->control_pid > 0 || @@ -3497,50 +3503,11 @@ static void show_unit_help(UnitStatusInfo *i) { return; } - STRV_FOREACH(p, i->documentation) { - - if (startswith(*p, "man:")) { - const char *args[4] = { "man", NULL, NULL, NULL }; - _cleanup_free_ char *page = NULL, *section = NULL; - char *e = NULL; - pid_t pid; - size_t k; - - k = strlen(*p); - - if ((*p)[k-1] == ')') - e = strrchr(*p, '('); - - if (e) { - page = strndup((*p) + 4, e - *p - 4); - section = strndup(e + 1, *p + k - e - 2); - if (!page || !section) { - log_oom(); - return; - } - - args[1] = section; - args[2] = page; - } else - args[1] = *p + 4; - - pid = fork(); - if (pid < 0) { - log_error("Failed to fork: %m"); - continue; - } - - if (pid == 0) { - /* Child */ - execvp(args[0], (char**) args); - log_error("Failed to execute man: %m"); - _exit(EXIT_FAILURE); - } - - wait_for_terminate(pid, NULL); - } else + STRV_FOREACH(p, i->documentation) + if (startswith(*p, "man:")) + show_man_page(*p + 4, false); + else log_info("Can't show: %s", *p); - } } static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) { @@ -3658,6 +3625,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->exit_code = (int) j; else if (streq(name, "ExecMainStatus")) i->exit_status = (int) j; + else if (streq(name, "StatusErrno")) + i->status_errno = (int) j; break; } @@ -5029,15 +4998,9 @@ static int enable_sysv_units(const char *verb, char **args) { STRV_FOREACH(k, paths.unit_path) { _cleanup_free_ char *path = NULL; - if (!isempty(arg_root)) - asprintf(&path, "%s/%s/%s", arg_root, *k, name); - else - asprintf(&path, "%s/%s", *k, name); - - if (!path) { - r = log_oom(); - goto finish; - } + path = path_join(arg_root, *k, name); + if (!path) + return log_oom(); found_native = access(path, F_OK) >= 0; if (found_native) @@ -5047,14 +5010,9 @@ static int enable_sysv_units(const char *verb, char **args) { if (found_native) continue; - if (!isempty(arg_root)) - asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name); - else - asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name); - if (!p) { - r = log_oom(); - goto finish; - } + p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name); + if (!p) + return log_oom(); p[strlen(p) - strlen(".service")] = 0; found_sysv = access(p, F_OK) >= 0; @@ -5076,18 +5034,15 @@ static int enable_sysv_units(const char *verb, char **args) { argv[c] = NULL; l = strv_join((char**)argv, " "); - if (!l) { - r = log_oom(); - goto finish; - } + if (!l) + return log_oom(); log_info("Executing %s", l); pid = fork(); if (pid < 0) { log_error("Failed to fork: %m"); - r = -errno; - goto finish; + return -errno; } else if (pid == 0) { /* Child */ @@ -5098,8 +5053,7 @@ static int enable_sysv_units(const char *verb, char **args) { j = wait_for_terminate(pid, &status); if (j < 0) { log_error("Failed to wait for child: %s", strerror(-r)); - r = j; - goto finish; + return j; } if (status.si_code == CLD_EXITED) { @@ -5113,17 +5067,12 @@ static int enable_sysv_units(const char *verb, char **args) { puts("disabled"); } - } else if (status.si_status != 0) { - r = -EINVAL; - goto finish; - } - } else { - r = -EPROTO; - goto finish; - } + } else if (status.si_status != 0) + return -EINVAL; + } else + return -EPROTO; } -finish: /* Drop all SysV units */ for (f = 0, t = 0; args[f]; f++) { @@ -5207,7 +5156,7 @@ static int enable_unit(sd_bus *bus, char **args) { } else if (streq(verb, "link")) r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); else if (streq(verb, "preset")) { - r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); carries_install_info = r; } else if (streq(verb, "mask")) r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); @@ -5229,7 +5178,7 @@ static int enable_unit(sd_bus *bus, char **args) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int expect_carries_install_info = false; - bool send_force = true; + bool send_force = true, send_preset_mode = false; const char *method; if (streq(verb, "enable")) { @@ -5244,7 +5193,13 @@ static int enable_unit(sd_bus *bus, char **args) { } else if (streq(verb, "link")) method = "LinkUnitFiles"; else if (streq(verb, "preset")) { - method = "PresetUnitFiles"; + + if (arg_preset_mode != UNIT_FILE_PRESET_FULL) { + method = "PresetUnitFilesWithMode"; + send_preset_mode = true; + } else + method = "PresetUnitFiles"; + expect_carries_install_info = true; } else if (streq(verb, "mask")) method = "MaskUnitFiles"; @@ -5268,6 +5223,12 @@ static int enable_unit(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); + if (send_preset_mode) { + r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode)); + if (r < 0) + return bus_log_create_error(r); + } + r = sd_bus_message_append(m, "b", arg_runtime); if (r < 0) return bus_log_create_error(r); @@ -5318,6 +5279,61 @@ finish: return r; } +static int preset_all(sd_bus *bus, char **args) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + int r; + + if (!bus || avoid_bus()) { + + r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); + if (r < 0) { + log_error("Operation failed: %s", strerror(-r)); + goto finish; + } + + if (!arg_quiet) + dump_unit_file_changes(changes, n_changes); + + r = 0; + + } else { + _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "PresetAllUnitFiles", + &error, + &reply, + "sbb", + unit_file_preset_mode_to_string(arg_preset_mode), + arg_runtime, + arg_force); + if (r < 0) { + log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + return r; + } + + r = deserialize_and_dump_unit_file_changes(reply); + if (r < 0) + return r; + + if (!arg_no_reload) + r = daemon_reload(bus, args); + else + r = 0; + } + +finish: + unit_file_changes_free(changes, n_changes); + + return r; +} + static int unit_is_enabled(sd_bus *bus, char **args) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -5392,6 +5408,30 @@ static int unit_is_enabled(sd_bus *bus, char **args) { return !enabled; } +static int is_system_running(sd_bus *bus, char **args) { + _cleanup_free_ char *state = NULL; + int r; + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SystemState", + NULL, + &state); + if (r < 0) { + if (!arg_quiet) + puts("unknown"); + return 0; + } + + if (!arg_quiet) + puts(state); + + return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE; +} + static int systemctl_help(void) { pager_open_if_enabled(); @@ -5435,6 +5475,8 @@ static int systemctl_help(void) { " --runtime Enable unit files only temporarily until next reboot\n" " -f --force When enabling unit files, override existing symlinks\n" " When shutting down, execute action immediately\n" + " --preset-mode= Specifies whether fully apply presets, or only enable,\n" + " or only disable\n" " --root=PATH Enable unit files in the specified root directory\n" " -n --lines=INTEGER Number of journal entries to show\n" " -o --output=STRING Change journal output mode (short, short-monotonic,\n" @@ -5475,6 +5517,8 @@ static int systemctl_help(void) { " reenable NAME... Reenable one or more unit files\n" " preset NAME... Enable/disable one or more unit files\n" " based on preset configuration\n" + " preset-all Enable/disable all unit files based on\n" + " preset configuration\n" " is-enabled NAME... Check whether unit files are enabled\n\n" " mask NAME... Mask one or more units\n" " unmask NAME... Unmask one or more units\n" @@ -5499,6 +5543,7 @@ static int systemctl_help(void) { " daemon-reload Reload systemd manager configuration\n" " daemon-reexec Reexecute systemd manager\n\n" "System Commands:\n" + " is-system-running Check whether system is fully running\n" " default Enter system default mode\n" " rescue Enter system rescue mode\n" " emergency Enter system emergency mode\n" @@ -5623,7 +5668,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_FORCE, ARG_PLAIN, ARG_STATE, - ARG_JOB_MODE + ARG_JOB_MODE, + ARG_PRESET_MODE, }; static const struct option options[] = { @@ -5665,6 +5711,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "plain", no_argument, NULL, ARG_PLAIN }, { "state", required_argument, NULL, ARG_STATE }, { "recursive", no_argument, NULL, 'r' }, + { "preset-mode", required_argument, NULL, ARG_PRESET_MODE }, {} }; @@ -5923,13 +5970,23 @@ static int systemctl_parse_argv(int argc, char *argv[]) { case 'r': if (geteuid() != 0) { - log_error("--recursive requires root priviliges."); + log_error("--recursive requires root privileges."); return -EPERM; } arg_recursive = true; break; + case ARG_PRESET_MODE: + + arg_preset_mode = unit_file_preset_mode_from_string(optarg); + if (arg_preset_mode < 0) { + log_error("Failed to parse preset mode: %s.", optarg); + return -EINVAL; + } + + break; + case '?': return -EINVAL; @@ -6481,6 +6538,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { { "is-enabled", MORE, 2, unit_is_enabled, NOBUS }, { "reenable", MORE, 2, enable_unit, NOBUS }, { "preset", MORE, 2, enable_unit, NOBUS }, + { "preset-all", EQUAL, 1, preset_all, NOBUS }, { "mask", MORE, 2, enable_unit, NOBUS }, { "unmask", MORE, 2, enable_unit, NOBUS }, { "link", MORE, 2, enable_unit, NOBUS }, @@ -6489,6 +6547,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { { "set-default", EQUAL, 2, set_default, NOBUS }, { "get-default", EQUAL, 1, get_default, NOBUS }, { "set-property", MORE, 3, set_property }, + { "is-system-running", EQUAL, 1, is_system_running }, {} }, *verb = verbs;