+ dbus_message_iter_recurse(&sub2, &sub3);
+
+ if (show_properties)
+ r = print_property(name, &sub3);
+ else
+ r = status_property(name, &sub3, &info);
+ if (r < 0) {
+ log_error("Failed to parse reply.");
+ return -EIO;
+ }
+
+ dbus_message_iter_next(&sub);
+ }
+
+ r = 0;
+
+ if (!show_properties) {
+ if (streq(verb, "help"))
+ show_unit_help(&info);
+ else
+ print_status_info(&info, ellipsized);
+ }
+
+ strv_free(info.documentation);
+ strv_free(info.dropin_paths);
+ strv_free(info.listen);
+
+ if (!streq_ptr(info.active_state, "active") &&
+ !streq_ptr(info.active_state, "reloading") &&
+ streq(verb, "status")) {
+ /* According to LSB: "program not running" */
+ /* 0: program is running or service is OK
+ * 1: program is dead and /var/run pid file exists
+ * 2: program is dead and /var/lock lock file exists
+ * 3: program is not running
+ * 4: program or service status is unknown
+ */
+ if (info.pid_file && access(info.pid_file, F_OK) == 0)
+ r = 1;
+ else
+ r = 3;
+ }
+
+ while ((p = info.exec)) {
+ LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
+ exec_status_info_free(p);
+ }
+
+ return r;
+}
+
+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;
+ int r;
+
+ dbus_error_init(&error);
+
+ r = bus_method_call_with_reply(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnitByPID",
+ &reply,
+ NULL,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_INVALID);
+ if (r < 0)
+ 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));
+ return -EIO;
+ }
+
+ 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,
+ bool *ellipsized) {
+ _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+ _cleanup_free_ struct unit_info *unit_infos = NULL;
+ unsigned c = 0;
+ const struct unit_info *u;
+ int r;
+
+ r = get_unit_list(bus, &reply, &unit_infos, &c);
+ if (r < 0)
+ return r;
+
+ qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+
+ for (u = unit_infos; u < unit_infos + c; u++) {
+ _cleanup_free_ char *p = NULL;
+
+ if (!output_show_unit(u))
+ continue;
+
+ p = unit_dbus_path_from_name(u->id);
+ if (!p)
+ return log_oom();
+
+ printf("%s -> '%s'\n", u->id, p);
+
+ r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
+
+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);
+
+ show_properties = streq(args[0], "show");
+ show_status = streq(args[0], "status");
+
+ if (show_properties)
+ pager_open_if_enabled();
+
+ /* 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, &ellipsized);
+
+ if (show_status && strv_length(args) <= 1)
+ 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 */
+
+ n = unit_name_mangle(*name);
+ if (!n)
+ 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, &ellipsized);
+ if (r != 0)
+ ret = r;
+
+ } 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();
+
+ 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, &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;
+}
+
+static int append_assignment(DBusMessageIter *iter, const char *assignment) {
+ const char *eq;
+ char *field;
+ DBusMessageIter sub;
+ int r;
+
+ assert(iter);
+ assert(assignment);
+
+ eq = strchr(assignment, '=');
+ if (!eq) {
+ log_error("Not an assignment: %s", assignment);
+ return -EINVAL;
+ }
+
+ field = strndupa(assignment, eq - assignment);
+ eq ++;
+
+ if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field))
+ return log_oom();
+
+ if (streq(field, "CPUAccounting") ||
+ streq(field, "MemoryAccounting") ||
+ streq(field, "BlockIOAccounting")) {
+ dbus_bool_t b;
+
+ r = parse_boolean(eq);
+ if (r < 0) {
+ log_error("Failed to parse boolean assignment %s.", assignment);
+ return -EINVAL;
+ }
+
+ b = r;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
+ return log_oom();
+
+ } else if (streq(field, "MemoryLimit")) {
+ off_t bytes;
+ uint64_t u;
+
+ r = parse_bytes(eq, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse bytes specification %s", assignment);
+ return -EINVAL;
+ }
+
+ u = bytes;
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
+ !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
+ return log_oom();
+
+ } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
+ uint64_t u;