X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=ba4f171fdafe44147add6d0ae7fb0512d6acd4fc;hp=24818492322fc98cecb8343345874afa7e2f74fc;hb=bbb8486e1709ee297a1eb803f88041e1da1fa436;hpb=96342de68d0d6de71a062d984dafd2a0905ed9fe diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 248184923..ba4f171fd 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include "install.h" #include "logs-show.h" #include "path-util.h" +#include "socket-util.h" static const char *arg_type = NULL; static const char *arg_load_state = NULL; @@ -74,7 +76,6 @@ static bool arg_no_block = false; static bool arg_no_legend = false; static bool arg_no_pager = false; static bool arg_no_wtmp = false; -static bool arg_no_sync = false; static bool arg_no_wall = false; static bool arg_no_reload = false; static bool arg_dry = false; @@ -99,6 +100,7 @@ static enum action { ACTION_EXIT, ACTION_SUSPEND, ACTION_HIBERNATE, + ACTION_HYBRID_SLEEP, ACTION_RUNLEVEL2, ACTION_RUNLEVEL3, ACTION_RUNLEVEL4, @@ -123,7 +125,6 @@ static enum transport { TRANSPORT_POLKIT } arg_transport = TRANSPORT_NORMAL; static const char *arg_host = NULL; -static bool arg_follow = false; static unsigned arg_lines = 10; static OutputMode arg_output = OUTPUT_SHORT; @@ -132,26 +133,8 @@ static bool private_bus = false; static int daemon_reload(DBusConnection *bus, char **args); static void halt_now(enum action a); -static bool on_tty(void) { - static int t = -1; - - /* Note that this is invoked relatively early, before we start - * the pager. That means the value we return reflects whether - * we originally were started on a tty, not if we currently - * are. But this is intended, since we want colour and so on - * when run in our own pager. */ - - if (_unlikely_(t < 0)) - t = isatty(STDOUT_FILENO) > 0; - - return t; -} - static void pager_open_if_enabled(void) { - /* Cache result before we open the pager */ - on_tty(); - if (arg_no_pager) return; @@ -186,6 +169,14 @@ static void polkit_agent_open_if_enabled(void) { } #endif +static const char *ansi_highlight(bool b) { + + if (!on_tty()) + return ""; + + return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF; +} + static const char *ansi_highlight_red(bool b) { if (!on_tty()) @@ -331,6 +322,7 @@ static bool output_show_unit(const struct unit_info *u) { static void output_units_list(const struct unit_info *unit_infos, unsigned c) { unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0; const struct unit_info *u; + int job_count = 0; max_id_len = sizeof("UNIT")-1; active_len = sizeof("ACTIVE")-1; @@ -345,14 +337,18 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { max_id_len = MAX(max_id_len, strlen(u->id)); active_len = MAX(active_len, strlen(u->active_state)); sub_len = MAX(sub_len, strlen(u->sub_state)); - if (u->job_id != 0) + if (u->job_id != 0) { job_len = MAX(job_len, strlen(u->job_type)); + job_count++; + } } if (!arg_full) { unsigned basic_len; id_len = MIN(max_id_len, 25); - basic_len = 5 + id_len + 6 + active_len + sub_len + job_len; + basic_len = 5 + id_len + 5 + active_len + sub_len; + if (job_count) + basic_len += job_len + 1; if (basic_len < (unsigned) columns()) { unsigned extra_len, incr; extra_len = columns() - basic_len; @@ -372,15 +368,6 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } else id_len = max_id_len; - if (!arg_no_legend) { - printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD", - active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB"); - if (!arg_full && arg_no_pager) - printf("%.*s\n", desc_len, "DESCRIPTION"); - else - printf("%s\n", "DESCRIPTION"); - } - for (u = unit_infos; u < unit_infos + c; u++) { char *e; const char *on_loaded, *off_loaded; @@ -389,6 +376,17 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (!output_show_unit(u)) continue; + if (!n_shown && !arg_no_legend) { + printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD", + active_len, "ACTIVE", sub_len, "SUB"); + if (job_count) + printf("%-*s ", job_len, "JOB"); + if (!arg_full && arg_no_pager) + printf("%.*s\n", desc_len, "DESCRIPTION"); + else + printf("%s\n", "DESCRIPTION"); + } + n_shown++; if (streq(u->load_state, "error")) { @@ -405,12 +403,12 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { e = arg_full ? NULL : ellipsize(u->id, id_len, 33); - printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ", + printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s", id_len, e ? e : u->id, on_loaded, u->load_state, off_loaded, on_active, active_len, u->active_state, sub_len, u->sub_state, off_active, - job_len, u->job_id ? u->job_type : ""); + job_count ? job_len + 1 : 0, u->job_id ? u->job_type : ""); if (!arg_full && arg_no_pager) printf("%.*s\n", desc_len, u->description); else @@ -420,15 +418,30 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } if (!arg_no_legend) { - printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n" - "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" - "SUB = The low-level unit activation state, values depend on unit type.\n" - "JOB = Pending job for the unit.\n"); + const char *on, *off; + + if (n_shown) { + printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n" + "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" + "SUB = The low-level unit activation state, values depend on unit type.\n"); + if (job_count) + printf("JOB = Pending job for the unit.\n"); + puts(""); + on = ansi_highlight(true); + off = ansi_highlight(false); + } else { + on = ansi_highlight_red(true); + off = ansi_highlight_red(false); + } if (arg_all) - printf("\n%u units listed.\n", n_shown); + printf("%s%u loaded units listed.%s\n" + "To show all installed unit files use 'systemctl list-unit-files'.\n", + on, n_shown, off); else - printf("\n%u units listed. Pass --all to see inactive units, too.\n", n_shown); + printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n" + "To show all installed unit files use 'systemctl list-unit-files'.\n", + on, n_shown, off); } } @@ -586,7 +599,8 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { if (u->state == UNIT_FILE_MASKED || u->state == UNIT_FILE_MASKED_RUNTIME || - u->state == UNIT_FILE_DISABLED) { + u->state == UNIT_FILE_DISABLED || + u->state == UNIT_FILE_INVALID) { on = ansi_highlight_red(true); off = ansi_highlight_red(false); } else if (u->state == UNIT_FILE_ENABLED) { @@ -1173,6 +1187,8 @@ finish: typedef struct WaitData { Set *set; + + char *name; char *result; } WaitData; @@ -1211,9 +1227,12 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me p = set_remove(d->set, (char*) path); free(p); - if (*result) + if (!isempty(result)) d->result = strdup(result); + if (!isempty(unit)) + d->name = strdup(unit); + goto finish; } #ifndef LEGACY @@ -1295,7 +1314,7 @@ static int enable_wait_for_jobs(DBusConnection *bus) { } static int wait_for_jobs(DBusConnection *bus, Set *s) { - int r; + int r = 0; WaitData d; assert(bus); @@ -1304,41 +1323,46 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { zero(d); d.set = s; - if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) { - log_error("Failed to add filter."); - r = -ENOMEM; - goto finish; - } + if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) + return log_oom(); - while (!set_isempty(s) && - dbus_connection_read_write_dispatch(bus, -1)) - ; + while (!set_isempty(s)) { - if (!arg_quiet && d.result) { - if (streq(d.result, "timeout")) - log_error("Job timed out."); - else if (streq(d.result, "canceled")) - log_error("Job canceled."); - else if (streq(d.result, "dependency")) - log_error("A dependency job failed. See system journal for details."); - else if (!streq(d.result, "done") && !streq(d.result, "skipped")) - log_error("Job failed. See system journal and 'systemctl status' for details."); - } + if (!dbus_connection_read_write_dispatch(bus, -1)) { + log_error("Disconnected from bus."); + return -ECONNREFUSED; + } - if (streq_ptr(d.result, "timeout")) - r = -ETIME; - else if (streq_ptr(d.result, "canceled")) - r = -ECANCELED; - else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped")) - r = -EIO; - else - r = 0; + if (!d.result) + goto free_name; - free(d.result); + if (!arg_quiet) { + if (streq(d.result, "timeout")) + log_error("Job for %s timed out.", strna(d.name)); + else if (streq(d.result, "canceled")) + log_error("Job for %s canceled.", strna(d.name)); + else if (streq(d.result, "dependency")) + log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name)); + else if (!streq(d.result, "done") && !streq(d.result, "skipped")) + log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name)); + } -finish: - /* This is slightly dirty, since we don't undo the filter registration. */ + if (streq_ptr(d.result, "timeout")) + r = -ETIME; + else if (streq_ptr(d.result, "canceled")) + r = -ECANCELED; + else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped")) + r = -EIO; + free(d.result); + d.result = NULL; + + free_name: + free(d.name); + d.name = NULL; + } + + dbus_connection_remove_filter(bus, wait_filter, &d); return r; } @@ -1432,22 +1456,26 @@ static void check_triggering_units( DBusConnection *bus, const char *unit_name) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub; char *service_trigger = NULL; const char *interface = "org.freedesktop.systemd1.Unit", *triggered_by_property = "TriggeredBy"; - char *unit_path = NULL, *n = NULL; + char _cleanup_free_ *unit_path = NULL, *n = NULL; bool print_warning_label = true; int r; n = unit_name_mangle(unit_name); - unit_path = unit_dbus_path_from_name(n ? n : unit_name); - free(n); + if (!n) { + log_oom(); + return; + } + + unit_path = unit_dbus_path_from_name(n); if (!unit_path) { - log_error("Could not allocate dbus path."); - goto finish; + log_oom(); + return; } r = bus_method_call_with_reply ( @@ -1462,13 +1490,12 @@ static void check_triggering_units( DBUS_TYPE_STRING, &triggered_by_property, DBUS_TYPE_INVALID); if (r) - goto finish; + return; if (!dbus_message_iter_init(reply, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { log_error("Failed to parse reply."); - goto finish; - + return; } dbus_message_iter_recurse(&iter, &sub); @@ -1479,14 +1506,14 @@ static void check_triggering_units( if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) { log_error("Failed to parse reply."); - goto finish; + return; } dbus_message_iter_get_basic(&sub, &service_trigger); r = check_one_unit(bus, service_trigger, true); if (r < 0) - goto finish; + return; if (r == 0) { if (print_warning_label) { log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name); @@ -1497,11 +1524,6 @@ static void check_triggering_units( dbus_message_iter_next(&sub); } -finish: - if (reply) - dbus_message_unref(reply); - - free(unit_path); } static int start_unit_one( @@ -1512,19 +1534,21 @@ static int start_unit_one( DBusError *error, Set *s) { - DBusMessage *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *path; int r; - char *n; + _cleanup_free_ char *n, *p = NULL; assert(method); assert(name); assert(mode); assert(error); - assert(arg_no_block || s); n = unit_name_mangle(name); - r = bus_method_call_with_reply ( + if (!n) + return log_oom(); + + r = bus_method_call_with_reply( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", @@ -1532,60 +1556,46 @@ static int start_unit_one( method, &reply, error, - DBUS_TYPE_STRING, n ? (const char **) &n : &name, + DBUS_TYPE_STRING, &n, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID); - free(n); if (r) { - if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL ) + if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL) /* There's always a fallback possible for * legacy actions. */ r = -EADDRNOTAVAIL; else log_error("Failed to issue method call: %s", bus_error_message(error)); - goto finish; + + return r; } if (!dbus_message_get_args(reply, error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { log_error("Failed to parse reply: %s", bus_error_message(error)); - r = -EIO; - goto finish; + return -EIO; } - if (need_daemon_reload(bus, name)) - log_warning("Warning: Unit file of created job changed on disk, 'systemctl %s daemon-reload' recommended.", - arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); - - if (!arg_no_block) { - char *p; + if (need_daemon_reload(bus, n)) + log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.", + n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user"); - if (!(p = strdup(path))) { - log_error("Failed to duplicate path."); - r = -ENOMEM; - goto finish; - } + if (s) { + p = strdup(path); + if (!p) + return log_oom(); - if ((r = set_put(s, p)) < 0) { - free(p); + r = set_put(s, p); + if (r < 0) { log_error("Failed to add path to set."); - goto finish; + return r; } - } - - /* When stopping a unit warn if it can still be triggered by - * another active unit (socket, path, timer) */ - if (!arg_quiet && streq(method, "StopUnit")) - check_triggering_units(bus, name); - - r = 0; -finish: - if (reply) - dbus_message_unref(reply); + p = NULL; + } - return r; + return 0; } static enum action verb_to_action(const char *verb) { @@ -1609,6 +1619,8 @@ static enum action verb_to_action(const char *verb) { return ACTION_SUSPEND; else if (streq(verb, "hibernate")) return ACTION_HIBERNATE; + else if (streq(verb, "hybrid-sleep")) + return ACTION_HYBRID_SLEEP; else return ACTION_INVALID; } @@ -1629,7 +1641,8 @@ static int start_unit(DBusConnection *bus, char **args) { [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET, [ACTION_EXIT] = SPECIAL_EXIT_TARGET, [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET, - [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET + [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, + [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET }; int r, ret = 0; @@ -1686,39 +1699,53 @@ static int start_unit(DBusConnection *bus, char **args) { } if (!arg_no_block) { - if ((ret = enable_wait_for_jobs(bus)) < 0) { + ret = enable_wait_for_jobs(bus); + if (ret < 0) { log_error("Could not watch jobs: %s", strerror(-ret)); goto finish; } - if (!(s = set_new(string_hash_func, string_compare_func))) { - log_error("Failed to allocate set."); - ret = -ENOMEM; + s = set_new(string_hash_func, string_compare_func); + if (!s) { + ret = log_oom(); goto finish; } } if (one_name) { - if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0) - goto finish; + ret = start_unit_one(bus, method, one_name, mode, &error, s); + if (ret < 0) + ret = translate_bus_error_to_exit_status(ret, &error); } else { - STRV_FOREACH(name, args+1) - if ((r = start_unit_one(bus, method, *name, mode, &error, s)) != 0) { + STRV_FOREACH(name, args+1) { + r = start_unit_one(bus, method, *name, mode, &error, s); + if (r < 0) { ret = translate_bus_error_to_exit_status(r, &error); dbus_error_free(&error); } + } } - if (!arg_no_block) - if ((r = wait_for_jobs(bus, s)) < 0) { + if (!arg_no_block) { + r = wait_for_jobs(bus, s); + if (r < 0) { ret = r; goto finish; } -finish: - if (s) - set_free_free(s); + /* When stopping units, warn if they can still be triggered by + * another active unit (socket, path, timer) */ + if (!arg_quiet && streq(method, "StopUnit")) { + if (one_name) + check_triggering_units(bus, one_name); + else + STRV_FOREACH(name, args+1) + check_triggering_units(bus, *name); + } + } +finish: + set_free_free(s); dbus_error_free(&error); return ret; @@ -1751,6 +1778,10 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) { method = "Hibernate"; break; + case ACTION_HYBRID_SLEEP: + method = "HybridSleep"; + break; + default: return -EINVAL; } @@ -1802,7 +1833,8 @@ static int start_special(DBusConnection *bus, char **args) { (a == ACTION_POWEROFF || a == ACTION_REBOOT || a == ACTION_SUSPEND || - a == ACTION_HIBERNATE)) { + a == ACTION_HIBERNATE || + a == ACTION_HYBRID_SLEEP)) { r = reboot_with_logind(bus, a); if (r >= 0) return r; @@ -2093,7 +2125,7 @@ static void print_status_info(UnitStatusInfo *i) { streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp : i->active_exit_timestamp; - s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp); + s1 = format_timestamp_relative(since1, sizeof(since1), timestamp); s2 = format_timestamp(since2, sizeof(since2), timestamp); if (s1) @@ -2104,7 +2136,7 @@ static void print_status_info(UnitStatusInfo *i) { printf("\n"); if (!i->condition_result && i->condition_timestamp > 0) { - s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp); + s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp); s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); if (s1) @@ -2260,15 +2292,19 @@ static void print_status_info(UnitStatusInfo *i) { if (i->id && arg_transport != TRANSPORT_SSH) { int flags = - arg_lines * OUTPUT_SHOW_ALL | - arg_follow * OUTPUT_FOLLOW | - !arg_quiet * OUTPUT_WARN_CUTOFF | - on_tty() * OUTPUT_COLOR; + arg_all * OUTPUT_SHOW_ALL | + (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | + on_tty() * OUTPUT_COLOR | + !arg_quiet * OUTPUT_WARN_CUTOFF; printf("\n"); - show_journal_by_unit(i->id, arg_output, 0, + show_journal_by_unit(stdout, + i->id, + arg_output, + 0, i->inactive_exit_timestamp_monotonic, - arg_lines, flags); + arg_lines, + flags); } if (i->need_daemon_reload) @@ -3312,12 +3348,13 @@ static int switch_root(DBusConnection *bus, char **args) { } static int set_environment(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; DBusError error; - int r; const char *method; - DBusMessageIter iter, sub; - char **name; + DBusMessageIter iter; + int r; + + assert(bus); dbus_error_init(&error); @@ -3325,38 +3362,22 @@ static int set_environment(DBusConnection *bus, char **args) { ? "SetEnvironment" : "UnsetEnvironment"; - if (!(m = dbus_message_new_method_call( - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - method))) { - - log_error("Could not allocate message."); - return -ENOMEM; - } + m = dbus_message_new_method_call( + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + method); + if (!m) + return log_oom(); dbus_message_iter_init_append(m, &iter); - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - STRV_FOREACH(name, args+1) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!dbus_message_iter_close_container(&iter, &sub)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } + r = bus_append_strv_iter(&iter, args + 1); + if (r < 0) + return log_oom(); - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { + reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); + if (!reply) { log_error("Failed to issue method call: %s", bus_error_message(&error)); r = -EIO; goto finish; @@ -3365,14 +3386,7 @@ static int set_environment(DBusConnection *bus, char **args) { r = 0; finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); - return r; } @@ -3396,7 +3410,7 @@ static int enable_sysv_units(char **args) { * afterwards only the native units remain */ zero(paths); - r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL); + r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL); if (r < 0) return r; @@ -3549,6 +3563,38 @@ finish: return r; } +static int mangle_names(char **original_names, char ***mangled_names) { + char **i, **l, **name; + + l = new(char*, strv_length(original_names) + 1); + if (!l) + return log_oom(); + + i = l; + STRV_FOREACH(name, original_names) { + + /* When enabling units qualified path names are OK, + * too, hence allow them explicitly. */ + + if (is_path(*name)) + *i = strdup(*name); + else + *i = unit_name_mangle(*name); + + if (!*i) { + strv_free(l); + return log_oom(); + } + + i++; + } + + *i = NULL; + *mangled_names = l; + + return 0; +} + static int enable_unit(DBusConnection *bus, char **args) { const char *verb = args[0]; UnitFileChange *changes = NULL; @@ -3557,6 +3603,7 @@ static int enable_unit(DBusConnection *bus, char **args) { DBusMessage *m = NULL, *reply = NULL; int r; DBusError error; + char **mangled_names = NULL; r = enable_sysv_units(args); if (r < 0) @@ -3602,6 +3649,7 @@ static int enable_unit(DBusConnection *bus, char **args) { } } + r = 0; } else { const char *method; bool send_force = true, expect_carries_install_info = false; @@ -3642,7 +3690,11 @@ static int enable_unit(DBusConnection *bus, char **args) { dbus_message_iter_init_append(m, &iter); - r = bus_append_strv_iter(&iter, args+1); + r = mangle_names(args+1, &mangled_names); + if(r < 0) + goto finish; + + r = bus_append_strv_iter(&iter, mangled_names); if (r < 0) { log_error("Failed to append unit files."); goto finish; @@ -3742,6 +3794,9 @@ finish: unit_file_changes_free(changes, n_changes); dbus_error_free(&error); + + strv_free(mangled_names); + return r; } @@ -3869,9 +3924,8 @@ static int systemctl_help(void) { " --root=PATH Enable unit files in the specified root directory\n" " --runtime Enable unit files only temporarily until next reboot\n" " -n --lines=INTEGER Journal entries to show\n" - " --follow Follow journal\n" " -o --output=STRING Change journal output mode (short, short-monotonic,\n" - " verbose, export, json, cat)\n\n" + " verbose, export, json, json-pretty, json-sse, cat)\n\n" "Unit Commands:\n" " list-units List loaded units\n" " start [NAME...] Start (activate) one or more units\n" @@ -3932,7 +3986,8 @@ static int systemctl_help(void) { " exit Request user instance exit\n" " switch-root [ROOT] [INIT] Change to a different root file system\n" " suspend Suspend the system\n" - " hibernate Hibernate the system\n", + " hibernate Hibernate the system\n" + " hybrid-sleep Hibernate and suspend the system\n", program_invocation_short_name); return 0; @@ -3949,7 +4004,6 @@ static int halt_help(void) { " -f --force Force immediate halt/power-off/reboot\n" " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n" " -d --no-wtmp Don't write wtmp record\n" - " -n --no-sync Don't sync before halt/power-off/reboot\n" " --no-wall Don't send wall message before halt/power-off/reboot\n", program_invocation_short_name, arg_action == ACTION_REBOOT ? "Reboot" : @@ -4004,6 +4058,22 @@ static int runlevel_help(void) { return 0; } +static int help_types(void) { + int i; + + puts("Available unit types:"); + for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++) + if (unit_type_table[i]) + puts(unit_type_table[i]); + + puts("\nAvailable unit load states: "); + for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++) + if (unit_type_table[i]) + puts(unit_load_state_table[i]); + + return 0; +} + static int systemctl_parse_argv(int argc, char *argv[]) { enum { @@ -4026,7 +4096,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_NO_ASK_PASSWORD, ARG_FAILED, ARG_RUNTIME, - ARG_FOLLOW, ARG_FORCE }; @@ -4060,7 +4129,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "privileged",no_argument, NULL, 'P' }, { "runtime", no_argument, NULL, ARG_RUNTIME }, { "lines", required_argument, NULL, 'n' }, - { "follow", no_argument, NULL, ARG_FOLLOW }, { "output", required_argument, NULL, 'o' }, { NULL, 0, NULL, 0 } }; @@ -4085,6 +4153,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return 0; case 't': + if (streq(optarg, "help")) { + help_types(); + return 0; + } + if (unit_type_from_string(optarg) >= 0) { arg_type = optarg; break; @@ -4095,6 +4168,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } log_error("Unkown unit type or load state '%s'.", optarg); + log_info("Use -t help to see a list of allowed values."); return -EINVAL; case 'p': { char **l; @@ -4180,14 +4254,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_force ++; break; - case ARG_FOLLOW: - arg_follow = true; - break; - case 'f': - /* -f is short for both --follow and --force! */ arg_force ++; - arg_follow = true; break; case ARG_NO_RELOAD: @@ -4271,7 +4339,6 @@ static int halt_parse_argv(int argc, char *argv[]) { { "force", no_argument, NULL, 'f' }, { "wtmp-only", no_argument, NULL, 'w' }, { "no-wtmp", no_argument, NULL, 'd' }, - { "no-sync", no_argument, NULL, 'n' }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, { NULL, 0, NULL, 0 } }; @@ -4317,16 +4384,13 @@ static int halt_parse_argv(int argc, char *argv[]) { arg_no_wtmp = true; break; - case 'n': - arg_no_sync = true; - break; - case ARG_NO_WALL: arg_no_wall = true; break; case 'i': case 'h': + case 'n': /* Compatibility nops */ break; @@ -4874,6 +4938,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "kexec", EQUAL, 1, start_special }, { "suspend", EQUAL, 1, start_special }, { "hibernate", EQUAL, 1, start_special }, + { "hybrid-sleep", EQUAL, 1, start_special }, { "default", EQUAL, 1, start_special }, { "rescue", EQUAL, 1, start_special }, { "emergency", EQUAL, 1, start_special }, @@ -5168,9 +5233,6 @@ static int halt_main(DBusConnection *bus) { } } - if (!arg_no_sync) - sync(); - if (arg_dry) return 0; @@ -5202,6 +5264,7 @@ int main(int argc, char*argv[]) { dbus_error_init(&error); + setlocale(LC_ALL, ""); log_parse_environment(); log_open();