X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl%2Fsystemctl.c;h=a8a86edd1fbeb647c1ef9639ab21e4e0951297ab;hp=c9f9981f9c7358b43b164b088cee8a811d72c1a5;hb=872c8faaf2009422a91d227ae0b5c6f04c9d2c69;hpb=9b9b3d36b8ffe5b41c1455bffd44a9d11efc8aee diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index c9f9981f9..a8a86edd1 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -72,6 +72,7 @@ static char **arg_types = NULL; static char **arg_states = NULL; static char **arg_properties = NULL; static bool arg_all = false; +static bool original_stdout_is_tty; static enum dependency { DEPENDENCY_FORWARD, DEPENDENCY_REVERSE, @@ -175,30 +176,6 @@ 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()) - return ""; - - return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF; -} - -static const char *ansi_highlight_green(bool b) { - - if (!on_tty()) - return ""; - - return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF; -} - static int translate_bus_error_to_exit_status(int r, const DBusError *error) { assert(error); @@ -333,7 +310,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { } } - if (!arg_full) { + if (!arg_full && original_stdout_is_tty) { unsigned basic_len; id_len = MIN(max_id_len, 25u); basic_len = 5 + id_len + 5 + active_len + sub_len; @@ -381,14 +358,14 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (streq(u->load_state, "error") || streq(u->load_state, "not-found")) { - on_loaded = on = ansi_highlight_red(true); - off_loaded = off = ansi_highlight_red(false); + on_loaded = on = ansi_highlight_red(); + off_loaded = off = ansi_highlight_off(); } else on_loaded = off_loaded = ""; if (streq(u->active_state, "failed")) { - on_active = on = ansi_highlight_red(true); - off_active = off = ansi_highlight_red(false); + on_active = on = ansi_highlight_red(); + off_active = off = ansi_highlight_off(); } else on_active = off_active = ""; @@ -400,7 +377,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { on_active, active_len, u->active_state, sub_len, u->sub_state, off_active, job_count ? job_len + 1 : 0, u->job_id ? u->job_type : ""); - if (!arg_full && arg_no_pager) + if (desc_len > 0) printf("%.*s\n", desc_len, u->description); else printf("%s\n", u->description); @@ -416,11 +393,11 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { if (job_count) printf("JOB = Pending job for the unit.\n"); puts(""); - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); } else { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } if (arg_all) @@ -494,7 +471,7 @@ static int list_units(DBusConnection *bus, char **args) { if (r < 0) return r; - qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info); + qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info); output_units_list(unit_infos, c); @@ -683,13 +660,13 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { printf("\n"); } - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); if (!arg_no_legend) printf("\n"); } else { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } if (!arg_no_legend) { @@ -756,8 +733,8 @@ static int list_sockets(DBusConnection *bus, char **args) { listen = triggered = NULL; /* avoid cleanup */ } - qsort(socket_infos, cs, sizeof(struct socket_info), - (__compar_fn_t) socket_info_compare); + qsort_safe(socket_infos, cs, sizeof(struct socket_info), + (__compar_fn_t) socket_info_compare); output_sockets_list(socket_infos, cs); @@ -771,7 +748,7 @@ static int list_sockets(DBusConnection *bus, char **args) { } free(socket_infos); - return 0; + return r; } static int compare_unit_file_list(const void *a, const void *b) { @@ -838,11 +815,11 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { u->state == UNIT_FILE_MASKED_RUNTIME || u->state == UNIT_FILE_DISABLED || u->state == UNIT_FILE_INVALID) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else if (u->state == UNIT_FILE_ENABLED) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); } else on = off = ""; @@ -1131,7 +1108,7 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, int leve if (r < 0) return r; - qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare); + qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare); STRV_FOREACH(c, deps) { if (strv_contains(u, *c)) { @@ -1250,8 +1227,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { assert(n == 0 || jobs); if (n == 0) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); printf("%sNo jobs running.%s\n", on, off); return; @@ -1287,8 +1264,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { _cleanup_free_ char *e = NULL; if (streq(j->state, "running")) { - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); } else on = off = ""; @@ -1301,8 +1278,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) { } } - on = ansi_highlight(true); - off = ansi_highlight(false); + on = ansi_highlight(); + off = ansi_highlight_off(); if (on_tty()) printf("\n%s%zu jobs listed%s.\n", on, n, off); @@ -1388,36 +1365,6 @@ static int list_jobs(DBusConnection *bus, char **args) { return 0; } -static int load_unit(DBusConnection *bus, char **args) { - char **name; - - assert(args); - - STRV_FOREACH(name, args+1) { - _cleanup_free_ char *n = NULL; - int r; - - n = unit_name_mangle(*name); - if (!n) - return log_oom(); - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "LoadUnit", - NULL, - NULL, - DBUS_TYPE_STRING, &n, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - } - - return 0; -} - static int cancel_job(DBusConnection *bus, char **args) { char **name; @@ -1549,6 +1496,7 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { uint32_t id; const char *path, *result, *unit; + char *r; if (dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &id, @@ -1557,7 +1505,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID)) { - free(set_remove(d->set, (char*) path)); + r = set_remove(d->set, (char*) path); + if (!r) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + free(r); if (!isempty(result)) d->result = strdup(result); @@ -1577,7 +1529,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me /* Compatibility with older systemd versions < * 183 during upgrades. This should be dropped * one day. */ - free(set_remove(d->set, (char*) path)); + r = set_remove(d->set, (char*) path); + if (!r) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + free(r); if (*result) d->result = strdup(result); @@ -2557,7 +2513,8 @@ typedef struct UnitStatusInfo { LIST_HEAD(ExecStatusInfo, exec); } UnitStatusInfo; -static void print_status_info(UnitStatusInfo *i) { +static void print_status_info(UnitStatusInfo *i, + bool *ellipsized) { ExecStatusInfo *p; const char *on, *off, *ss; usec_t timestamp; @@ -2588,8 +2545,8 @@ static void print_status_info(UnitStatusInfo *i) { printf(" Follow: unit currently follows state of %s\n", i->following); if (streq_ptr(i->load_state, "error")) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2639,11 +2596,11 @@ static void print_status_info(UnitStatusInfo *i) { ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state; if (streq_ptr(i->active_state, "failed")) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) { - on = ansi_highlight_green(true); - off = ansi_highlight_green(false); + on = ansi_highlight_green(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2718,8 +2675,8 @@ static void print_status_info(UnitStatusInfo *i) { good = is_clean_exit_lsb(p->code, p->status, NULL); if (!good) { - on = ansi_highlight_red(true); - off = ansi_highlight_red(false); + on = ansi_highlight_red(); + off = ansi_highlight_off(); } else on = off = ""; @@ -2833,13 +2790,14 @@ static void print_status_info(UnitStatusInfo *i) { arg_lines, getuid(), flags, - arg_scope == UNIT_FILE_SYSTEM); + arg_scope == UNIT_FILE_SYSTEM, + ellipsized); } if (i->need_daemon_reload) printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n", - ansi_highlight_red(true), - ansi_highlight_red(false), + ansi_highlight_red(), + ansi_highlight_off(), arg_scope == UNIT_FILE_SYSTEM ? "" : "--user "); } @@ -3367,6 +3325,24 @@ static int print_property(const char *name, DBusMessageIter *iter) { } return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "BlockIODeviceWeight")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *path; + uint64_t weight; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &weight, false) >= 0) + printf("%s=%s %" PRIu64 "\n", name, strna(path), weight); + + dbus_message_iter_next(&sub); + } + return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) { DBusMessageIter sub, sub2; @@ -3399,7 +3375,12 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; } -static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) { +static int show_one(const char *verb, + DBusConnection *bus, + const char *path, + bool show_properties, + bool *new_line, + bool *ellipsized) { _cleanup_free_ DBusMessage *reply = NULL; const char *interface = ""; int r; @@ -3469,7 +3450,7 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo if (streq(verb, "help")) show_unit_help(&info); else - print_status_info(&info); + print_status_info(&info, ellipsized); } strv_free(info.documentation); @@ -3500,7 +3481,11 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo return r; } -static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) { +static int show_one_by_pid(const char *verb, + DBusConnection *bus, + uint32_t pid, + bool *new_line, + bool *ellipsized) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; const char *path = NULL; _cleanup_dbus_error_free_ DBusError error; @@ -3528,11 +3513,15 @@ static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, return -EIO; } - r = show_one(verb, bus, path, false, new_line); + r = show_one(verb, bus, path, false, new_line, ellipsized); return r; } -static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) { +static int show_all(const char* verb, + DBusConnection *bus, + bool show_properties, + bool *new_line, + bool *ellipsized) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; _cleanup_free_ struct unit_info *unit_infos = NULL; unsigned c = 0; @@ -3543,7 +3532,7 @@ static int show_all(const char* verb, DBusConnection *bus, bool show_properties, if (r < 0) return r; - qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info); + qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info); for (u = unit_infos; u < unit_infos + c; u++) { _cleanup_free_ char *p = NULL; @@ -3557,7 +3546,7 @@ static int show_all(const char* verb, DBusConnection *bus, bool show_properties, printf("%s -> '%s'\n", u->id, p); - r = show_one(verb, bus, p, show_properties, new_line); + r = show_one(verb, bus, p, show_properties, new_line, ellipsized); if (r != 0) return r; } @@ -3569,6 +3558,7 @@ static int show(DBusConnection *bus, char **args) { int r, ret = 0; bool show_properties, show_status, new_line = false; char **name; + bool ellipsized = false; assert(bus); assert(args); @@ -3582,48 +3572,51 @@ static int show(DBusConnection *bus, char **args) { /* If no argument is specified inspect the manager itself */ if (show_properties && strv_length(args) <= 1) - return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line); + return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); if (show_status && strv_length(args) <= 1) - return show_all(args[0], bus, false, &new_line); - - STRV_FOREACH(name, args+1) { - uint32_t id; + ret = show_all(args[0], bus, false, &new_line, &ellipsized); + else + STRV_FOREACH(name, args+1) { + uint32_t id; - if (safe_atou32(*name, &id) < 0) { - _cleanup_free_ char *p = NULL, *n = NULL; - /* Interpret as unit name */ + if (safe_atou32(*name, &id) < 0) { + _cleanup_free_ char *p = NULL, *n = NULL; + /* Interpret as unit name */ - n = unit_name_mangle(*name); - if (!n) - return log_oom(); + n = unit_name_mangle(*name); + if (!n) + return log_oom(); - p = unit_dbus_path_from_name(n); - if (!p) - return log_oom(); + p = unit_dbus_path_from_name(n); + if (!p) + return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line); - if (r != 0) - ret = r; + r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized); + if (r != 0) + ret = r; - } else if (show_properties) { - _cleanup_free_ char *p = NULL; + } else if (show_properties) { + _cleanup_free_ char *p = NULL; - /* Interpret as job id */ - if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) - return log_oom(); + /* Interpret as job id */ + if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) + return log_oom(); - r = show_one(args[0], bus, p, show_properties, &new_line); - if (r != 0) - ret = r; + r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized); + if (r != 0) + ret = r; - } else { - /* Interpret as PID */ - r = show_one_by_pid(args[0], bus, id, &new_line); - if (r != 0) - ret = r; + } else { + /* Interpret as PID */ + r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized); + if (r != 0) + ret = r; + } } - } + + if (ellipsized && !arg_quiet) + printf("Hint: Some lines were ellipsized, use -l to show in full.\n"); return ret; } @@ -3665,7 +3658,7 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b)) return log_oom(); - } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) { + } else if (streq(field, "MemoryLimit")) { off_t bytes; uint64_t u; @@ -3720,6 +3713,11 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { rwm = ""; } + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) || @@ -3730,6 +3728,94 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { if (!dbus_message_iter_close_container(&sub, &sub2)) return log_oom(); + } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) { + DBusMessageIter sub2; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) || + !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2)) + return log_oom(); + + if (!isempty(eq)) { + const char *path, *bandwidth; + DBusMessageIter sub3; + uint64_t u; + off_t bytes; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + bandwidth = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = parse_bytes(bandwidth, &bytes); + if (r < 0) { + log_error("Failed to parse byte value %s.", bandwidth); + return -EINVAL; + } + + u = (uint64_t) bytes; + + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) || + !dbus_message_iter_close_container(&sub2, &sub3)) + return log_oom(); + } + + if (!dbus_message_iter_close_container(&sub, &sub2)) + return log_oom(); + + } else if (streq(field, "BlockIODeviceWeight")) { + DBusMessageIter sub2; + + if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) || + !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2)) + return log_oom(); + + if (!isempty(eq)) { + const char *path, *weight; + DBusMessageIter sub3; + uint64_t u; + char *e; + + e = strchr(eq, ' '); + if (e) { + path = strndupa(eq, e - eq); + weight = e+1; + } else { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + if (!path_startswith(path, "/dev")) { + log_error("%s is not a device file in /dev.", path); + return -EINVAL; + } + + r = safe_atou64(weight, &u); + if (r < 0) { + log_error("Failed to parse %s value %s.", field, weight); + return -EINVAL; + } + if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) || + !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) || + !dbus_message_iter_close_container(&sub2, &sub3)) + return log_oom(); + } + + if (!dbus_message_iter_close_container(&sub, &sub2)) + return log_oom(); + } else { log_error("Unknown assignment %s.", assignment); return -EINVAL; @@ -3743,7 +3829,8 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) { static int set_property(DBusConnection *bus, char **args) { - _cleanup_free_ DBusMessage *m = NULL, *reply = NULL; + _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; + _cleanup_free_ char *n = NULL; DBusMessageIter iter, sub; dbus_bool_t runtime; DBusError error; @@ -3764,7 +3851,11 @@ static int set_property(DBusConnection *bus, char **args) { runtime = arg_runtime; - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[1]) || + n = unit_name_mangle(args[1]); + if (!n) + return log_oom(); + + if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) || !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) || !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub)) return log_oom(); @@ -3797,40 +3888,6 @@ static int set_property(DBusConnection *bus, char **args) { return 0; } -static int dump(DBusConnection *bus, char **args) { - _cleanup_free_ DBusMessage *reply = NULL; - DBusError error; - int r; - const char *text; - - dbus_error_init(&error); - - pager_open_if_enabled(); - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "Dump", - &reply, - NULL, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - - if (!dbus_message_get_args(reply, &error, - DBUS_TYPE_STRING, &text, - DBUS_TYPE_INVALID)) { - log_error("Failed to parse reply: %s", bus_error_message(&error)); - dbus_error_free(&error); - return -EIO; - } - - fputs(text, stdout); - return 0; -} - static int snapshot(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusError error; @@ -4161,11 +4218,10 @@ static int set_environment(DBusConnection *bus, char **args) { return 0; } -static int enable_sysv_units(char **args) { +static int enable_sysv_units(const char *verb, char **args) { int r = 0; #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG) - const char *verb = args[0]; unsigned f = 1, t = 1; LookupPaths paths = {}; @@ -4185,7 +4241,7 @@ static int enable_sysv_units(char **args) { return r; r = 0; - for (f = 1; args[f]; f++) { + for (f = 0; args[f]; f++) { const char *name; _cleanup_free_ char *p = NULL, *q = NULL; bool found_native = false, found_sysv; @@ -4308,7 +4364,7 @@ finish: lookup_paths_free(&paths); /* Drop all SysV units */ - for (f = 1, t = 1; args[f]; f++) { + for (f = 0, t = 0; args[f]; f++) { if (isempty(args[f])) continue; @@ -4366,16 +4422,16 @@ static int enable_unit(DBusConnection *bus, char **args) { dbus_error_init(&error); - r = enable_sysv_units(args); - if (r < 0) - return r; - if (!args[1]) return 0; r = mangle_names(args+1, &mangled_names); if (r < 0) - goto finish; + return r; + + r = enable_sysv_units(verb, mangled_names); + if (r < 0) + return r; if (!bus || avoid_bus()) { if (streq(verb, "enable")) { @@ -4561,62 +4617,21 @@ finish: return r; } -static int set_log_level(DBusConnection *bus, char **args) { - _cleanup_dbus_error_free_ DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - DBusMessageIter iter, sub; - const char* property = "LogLevel"; - const char* interface = "org.freedesktop.systemd1.Manager"; - const char* value; - - assert(bus); - assert(args); - - value = args[1]; - dbus_error_init(&error); - - m = dbus_message_new_method_call("org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.DBus.Properties", - "Set"); - if (!m) - return log_oom(); - - dbus_message_iter_init_append(m, &iter); - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub)) - return log_oom(); - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) { - dbus_message_iter_abandon_container(&iter, &sub); - return log_oom(); - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - return log_oom(); - - 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)); - return -EIO; - } - - return 0; -} - static int unit_is_enabled(DBusConnection *bus, char **args) { _cleanup_dbus_error_free_ DBusError error; int r; _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; bool enabled; char **name; - char *n; + _cleanup_strv_free_ char **mangled_names = NULL; dbus_error_init(&error); - r = enable_sysv_units(args); + r = mangle_names(args+1, &mangled_names); + if (r < 0) + return r; + + r = enable_sysv_units(args[0], mangled_names); if (r < 0) return r; @@ -4624,16 +4639,10 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { if (!bus || avoid_bus()) { - STRV_FOREACH(name, args+1) { + STRV_FOREACH(name, mangled_names) { UnitFileState state; - n = unit_name_mangle(*name); - if (!n) - return log_oom(); - - state = unit_file_get_state(arg_scope, arg_root, n); - - free(n); + state = unit_file_get_state(arg_scope, arg_root, *name); if (state < 0) return state; @@ -4648,13 +4657,9 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { } } else { - STRV_FOREACH(name, args+1) { + STRV_FOREACH(name, mangled_names) { const char *s; - n = unit_name_mangle(*name); - if (!n) - return log_oom(); - r = bus_method_call_with_reply ( bus, "org.freedesktop.systemd1", @@ -4663,11 +4668,9 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { "GetUnitFileState", &reply, NULL, - DBUS_TYPE_STRING, &n, + DBUS_TYPE_STRING, name, DBUS_TYPE_INVALID); - free(n); - if (r) return r; @@ -4703,7 +4706,7 @@ static int systemctl_help(void) { " -h --help Show this help\n" " --version Show package version\n" " -t --type=TYPE List only units of a particular type\n" - " --state=STATE Show only units with particular LOAD or SUB or ACTIVE state\n" + " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n" " -p --property=NAME Show only properties by this name\n" " -a --all Show all loaded units/properties, including dead/empty\n" " ones. To list all units installed on the system, use\n" @@ -4712,10 +4715,11 @@ static int systemctl_help(void) { " -l --full Don't ellipsize unit names on output\n" " --fail When queueing a new job, fail if conflicting jobs are\n" " pending\n" - " --irreversible Create jobs which cannot be implicitly cancelled\n" - " --show-types When showing sockets, explicitly show their type\n" + " --irreversible When queueing a new job, make sure it cannot be implicitly\n" + " cancelled\n" " --ignore-dependencies\n" " When queueing a new job, ignore all its dependencies\n" + " --show-types When showing sockets, explicitly show their type\n" " -i --ignore-inhibitors\n" " When shutting down or sleeping, ignore inhibitors\n" " --kill-who=WHO Who to send signal to\n" @@ -4735,11 +4739,11 @@ static int systemctl_help(void) { " --system Connect to system manager\n" " --user Connect to user service manager\n" " --global Enable/disable unit files globally\n" + " --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" " --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" + " -n --lines=INTEGER Numer of journal entries to show\n" " -o --output=STRING Change journal output mode (short, short-monotonic,\n" " verbose, export, json, json-pretty, json-sse, cat)\n\n" "Unit Commands:\n" @@ -4766,7 +4770,6 @@ static int systemctl_help(void) { " help [NAME...|PID...] Show manual for one or more units\n" " reset-failed [NAME...] Reset failed state for all, one, or more\n" " units\n" - " load [NAME...] Load one or more units\n" " list-dependencies [NAME] Recursively show units which are required\n" " or wanted by this unit or by which this\n" " unit is required or wanted\n\n" @@ -4777,26 +4780,23 @@ 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" + " 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" " link [PATH...] Link one or more units files into\n" " the search path\n" " get-default Get the name of the default target\n" - " set-default NAME Set the default target\n" - " is-enabled [NAME...] Check whether unit files are enabled\n\n" + " set-default NAME Set the default target\n\n" "Job Commands:\n" " list-jobs List jobs\n" " cancel [JOB...] Cancel all, one, or more jobs\n\n" - "Status Commands:\n" - " dump Dump server status\n" "Snapshot Commands:\n" " snapshot [NAME] Create a snapshot\n" " delete [NAME...] Remove one or more snapshots\n\n" "Environment Commands:\n" " show-environment Dump environment\n" " set-environment [NAME=VALUE...] Set one or more environment variables\n" - " unset-environment [NAME...] Unset one or more environment variables\n" - " set-log-level LEVEL Set logging threshold for systemd\n\n" + " unset-environment [NAME...] Unset one or more environment variables\n\n" "Manager Lifecycle Commands:\n" " daemon-reload Reload systemd manager configuration\n" " daemon-reexec Reexecute systemd manager\n\n" @@ -4927,43 +4927,43 @@ static int systemctl_parse_argv(int argc, char *argv[]) { }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "type", required_argument, NULL, 't' }, - { "property", required_argument, NULL, 'p' }, - { "all", no_argument, NULL, 'a' }, - { "reverse", no_argument, NULL, ARG_REVERSE }, - { "after", no_argument, NULL, ARG_AFTER }, - { "before", no_argument, NULL, ARG_BEFORE }, - { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, - { "failed", no_argument, NULL, ARG_FAILED }, - { "full", no_argument, NULL, 'l' }, - { "fail", no_argument, NULL, ARG_FAIL }, - { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, - { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, - { "ignore-inhibitors", no_argument, NULL, 'i' }, - { "user", no_argument, NULL, ARG_USER }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "global", no_argument, NULL, ARG_GLOBAL }, - { "no-block", no_argument, NULL, ARG_NO_BLOCK }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-wall", no_argument, NULL, ARG_NO_WALL }, - { "quiet", no_argument, NULL, 'q' }, - { "root", required_argument, NULL, ARG_ROOT }, - { "force", no_argument, NULL, ARG_FORCE }, - { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, - { "kill-who", required_argument, NULL, ARG_KILL_WHO }, - { "signal", required_argument, NULL, 's' }, - { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, - { "host", required_argument, NULL, 'H' }, - { "privileged",no_argument, NULL, 'P' }, - { "runtime", no_argument, NULL, ARG_RUNTIME }, - { "lines", required_argument, NULL, 'n' }, - { "output", required_argument, NULL, 'o' }, - { "plain", no_argument, NULL, ARG_PLAIN }, - { "state", required_argument, NULL, ARG_STATE }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "property", required_argument, NULL, 'p' }, + { "all", no_argument, NULL, 'a' }, + { "reverse", no_argument, NULL, ARG_REVERSE }, + { "after", no_argument, NULL, ARG_AFTER }, + { "before", no_argument, NULL, ARG_BEFORE }, + { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, + { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */ + { "full", no_argument, NULL, 'l' }, + { "fail", no_argument, NULL, ARG_FAIL }, + { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, + { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, + { "ignore-inhibitors", no_argument, NULL, 'i' }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, + { "global", no_argument, NULL, ARG_GLOBAL }, + { "no-block", no_argument, NULL, ARG_NO_BLOCK }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-wall", no_argument, NULL, ARG_NO_WALL }, + { "quiet", no_argument, NULL, 'q' }, + { "root", required_argument, NULL, ARG_ROOT }, + { "force", no_argument, NULL, ARG_FORCE }, + { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, + { "kill-who", required_argument, NULL, ARG_KILL_WHO }, + { "signal", required_argument, NULL, 's' }, + { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "host", required_argument, NULL, 'H' }, + { "privileged", no_argument, NULL, 'P' }, + { "runtime", no_argument, NULL, ARG_RUNTIME }, + { "lines", required_argument, NULL, 'n' }, + { "output", required_argument, NULL, 'o' }, + { "plain", no_argument, NULL, ARG_PLAIN }, + { "state", required_argument, NULL, ARG_STATE }, + { NULL, 0, NULL, 0 } }; int c; @@ -5669,94 +5669,6 @@ _pure_ static int action_to_runlevel(void) { return table[arg_action]; } -static int talk_upstart(void) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - _cleanup_dbus_error_free_ DBusError error; - int previous, rl, r; - char - env1_buf[] = "RUNLEVEL=X", - env2_buf[] = "PREVLEVEL=X"; - char *env1 = env1_buf, *env2 = env2_buf; - const char *emit = "runlevel"; - dbus_bool_t b_false = FALSE; - DBusMessageIter iter, sub; - DBusConnection *bus; - - dbus_error_init(&error); - - if (!(rl = action_to_runlevel())) - return 0; - - if (utmp_get_runlevel(&previous, NULL) < 0) - previous = 'N'; - - if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) { - if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) { - r = 0; - goto finish; - } - - log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - if ((r = bus_check_peercred(bus)) < 0) { - log_error("Failed to verify owner of bus."); - goto finish; - } - - if (!(m = dbus_message_new_method_call( - "com.ubuntu.Upstart", - "/com/ubuntu/Upstart", - "com.ubuntu.Upstart0_6", - "EmitEvent"))) { - - log_error("Could not allocate message."); - r = -ENOMEM; - goto finish; - } - - dbus_message_iter_init_append(m, &iter); - - env1_buf[sizeof(env1_buf)-2] = rl; - env2_buf[sizeof(env2_buf)-2] = previous; - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) || - !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) { - log_error("Could not append arguments to message."); - r = -ENOMEM; - goto finish; - } - - if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) { - - if (bus_error_is_no_service(&error)) { - r = -EADDRNOTAVAIL; - goto finish; - } - - log_error("Failed to issue method call: %s", bus_error_message(&error)); - r = -EIO; - goto finish; - } - - r = 1; - -finish: - if (bus) { - dbus_connection_flush(bus); - dbus_connection_close(bus); - dbus_connection_unref(bus); - } - - return r; -} - static int talk_initctl(void) { struct init_request request = {}; int r; @@ -5808,7 +5720,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "list-sockets", LESS, 1, list_sockets }, { "list-jobs", EQUAL, 1, list_jobs }, { "clear-jobs", EQUAL, 1, daemon_reload }, - { "load", MORE, 2, load_unit }, { "cancel", MORE, 2, cancel_job }, { "start", MORE, 2, start_unit }, { "stop", MORE, 2, start_unit }, @@ -5829,7 +5740,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "show", MORE, 1, show }, { "status", MORE, 1, show }, { "help", MORE, 2, show }, - { "dump", EQUAL, 1, dump }, { "snapshot", LESS, 2, snapshot }, { "delete", MORE, 2, delete_snapshot }, { "daemon-reload", EQUAL, 1, daemon_reload }, @@ -5861,7 +5771,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "list-dependencies", LESS, 2, list_dependencies }, { "set-default", EQUAL, 2, enable_unit }, { "get-default", LESS, 1, get_default }, - { "set-log-level", EQUAL, 2, set_log_level }, { "set-property", MORE, 3, set_property }, }; @@ -6031,11 +5940,6 @@ static int start_with_fallback(DBusConnection *bus) { goto done; } - /* Hmm, talking to systemd via D-Bus didn't work. Then - * let's try to talk to Upstart via D-Bus. */ - if (talk_upstart() > 0) - goto done; - /* Nothing else worked, so let's try * /dev/initctl */ if (talk_initctl() > 0) @@ -6177,6 +6081,11 @@ int main(int argc, char*argv[]) { log_parse_environment(); log_open(); + /* Explicitly not on_tty() to avoid setting cached value. + * This becomes relevant for piping output which might be + * ellipsized. */ + original_stdout_is_tty = isatty(STDOUT_FILENO); + r = parse_argv(argc, argv); if (r < 0) goto finish;