+ r = sd_bus_message_peek_type(reply, NULL, &contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (show_properties)
+ r = print_property(name, reply, contents);
+ else
+ r = status_property(name, reply, &info, contents);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ 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(exec, info.exec, p);
+ exec_status_info_free(p);
+ }
+
+ return r;
+}
+
+static int get_unit_dbus_path_by_pid(
+ sd_bus *bus,
+ uint32_t pid,
+ char **unit) {
+
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ int r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnitByPID",
+ &error,
+ &reply,
+ "u", pid);
+ if (r < 0) {
+ log_error("Failed to get unit for PID %lu: %s", (unsigned long) pid, bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_read(reply, "o", unit);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 0;
+}
+
+static int show_all(
+ const char* verb,
+ sd_bus *bus,
+ bool show_properties,
+ bool *new_line,
+ bool *ellipsized) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_free_ UnitInfo *unit_infos = NULL;
+ const UnitInfo *u;
+ unsigned c;
+ int r;
+
+ r = get_unit_list(bus, &reply, &unit_infos);
+ if (r < 0)
+ return r;
+
+ pager_open_if_enabled();
+
+ c = (unsigned) r;
+
+ qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
+
+ for (u = unit_infos; u < unit_infos + c; u++) {
+ _cleanup_free_ char *p = NULL;
+
+ if (!output_show_unit(u, NULL))
+ continue;
+
+ p = unit_dbus_path_from_name(u->id);
+ if (!p)
+ return log_oom();
+
+ r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int cat(sd_bus *bus, char **args) {
+ int r = 0;
+ char **name;
+
+ _cleanup_free_ char *unit = NULL, *n = NULL;
+
+ assert(bus);
+ assert(args);
+
+ pager_open_if_enabled();
+
+ STRV_FOREACH(name, args+1) {
+ _cleanup_free_ char *fragment_path = NULL;
+ _cleanup_strv_free_ char **dropin_paths = NULL;
+ sd_bus_error error;
+ char **path;
+
+ n = unit_name_mangle(*name);
+ if (!n)
+ return log_oom();
+
+ unit = unit_dbus_path_from_name(n);
+ if (!unit)
+ return log_oom();
+
+ if (need_daemon_reload(bus, n) > 0)
+ log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
+ n, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ unit,
+ "org.freedesktop.systemd1.Unit",
+ "FragmentPath",
+ &error,
+ &fragment_path);
+ if (r < 0) {
+ log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
+ continue;
+ }
+
+ r = sd_bus_get_property_strv(
+ bus,
+ "org.freedesktop.systemd1",
+ unit,
+ "org.freedesktop.systemd1.Unit",
+ "DropInPaths",
+ &error,
+ &dropin_paths);
+ if (r < 0) {
+ log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
+ continue;
+ }
+
+ if (!isempty(fragment_path)) {
+ fprintf(stdout, "# %s\n", fragment_path);
+ fflush(stdout);
+ r = sendfile_full(STDOUT_FILENO, fragment_path);
+ if (r < 0) {
+ log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
+ continue;
+ }
+ }
+
+ STRV_FOREACH(path, dropin_paths) {
+ fprintf(stdout, "%s# %s\n",
+ isempty(fragment_path) && path == dropin_paths ? "" : "\n",
+ *path);
+ fflush(stdout);
+ r = sendfile_full(STDOUT_FILENO, *path);
+ if (r < 0) {
+ log_warning("Failed to cat %s: %s", *path, strerror(-r));
+ continue;
+ }
+ }
+ }
+
+ return r;
+}
+
+static int show(sd_bus *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) {
+ _cleanup_free_ char *unit = NULL;
+ uint32_t id;
+
+ if (safe_atou32(*name, &id) < 0) {
+ _cleanup_free_ char *n = NULL;
+ /* Interpret as unit name */
+
+ n = unit_name_mangle(*name);
+ if (!n)
+ return log_oom();
+
+ unit = unit_dbus_path_from_name(n);
+ if (!unit)
+ return log_oom();
+
+ } else if (show_properties) {
+ /* Interpret as job id */
+ if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
+ return log_oom();
+
+ } else {
+ /* Interpret as PID */
+ r = get_unit_dbus_path_by_pid(bus, id, &unit);
+ if (r < 0)
+ ret = r;
+ }
+
+ show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized);