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=a635891bc015fc94124c71a875fc9dc86e1991d2;hb=872c8faaf2009422a91d227ae0b5c6f04c9d2c69;hpb=94e0bd7db1d7ca8ab7f738cdab1d014241f5b225 diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a635891bc..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, @@ -309,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; @@ -376,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); @@ -470,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); @@ -732,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); @@ -747,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) { @@ -1107,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)) { @@ -1495,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, @@ -1503,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); @@ -1523,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); @@ -3315,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; @@ -3504,7 +3532,7 @@ static int show_all(const char* verb, 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; @@ -3630,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; @@ -3685,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) || @@ -3695,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; @@ -3708,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; @@ -3729,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(); @@ -4092,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 = {}; @@ -4116,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; @@ -4239,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; @@ -4297,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")) { @@ -4498,11 +4623,15 @@ static int unit_is_enabled(DBusConnection *bus, char **args) { _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; @@ -4510,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; @@ -4534,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", @@ -4549,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; @@ -5552,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; @@ -5911,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) @@ -6057,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;