chiark / gitweb /
systemctl: make sure set-property mangles unit names
[elogind.git] / src / systemctl / systemctl.c
index 8ec1824f3b55819e4c3d0d48a091d618fdbaabc7..eede616e50ae6f8ba03ebff3ffbdce71ca55bba3 100644 (file)
@@ -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);
@@ -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);
@@ -2503,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;
@@ -2779,7 +2790,8 @@ 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)
@@ -3313,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;
 
@@ -3345,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;
@@ -3415,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);
@@ -3446,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;
@@ -3474,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;
@@ -3503,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;
         }
@@ -3515,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);
@@ -3528,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;
 }
@@ -3611,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;
 
@@ -3666,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) ||
@@ -3676,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;
@@ -3689,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;
@@ -3710,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();
@@ -4650,7 +4795,7 @@ static int systemctl_help(void) {
                "  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"
+               "  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"
@@ -6038,6 +6183,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;