summaryrefslogtreecommitdiffstats
path: root/src/systemctl/systemctl-list-jobs.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:00:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:00:47 +0000
commit2cb7e0aaedad73b076ea18c6900b0e86c5760d79 (patch)
treeda68ca54bb79f4080079bf0828acda937593a4e1 /src/systemctl/systemctl-list-jobs.c
parentInitial commit. (diff)
downloadsystemd-2cb7e0aaedad73b076ea18c6900b0e86c5760d79.tar.xz
systemd-2cb7e0aaedad73b076ea18c6900b0e86c5760d79.zip
Adding upstream version 247.3.upstream/247.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/systemctl/systemctl-list-jobs.c')
-rw-r--r--src/systemctl/systemctl-list-jobs.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/systemctl/systemctl-list-jobs.c b/src/systemctl/systemctl-list-jobs.c
new file mode 100644
index 0000000..8b028c0
--- /dev/null
+++ b/src/systemctl/systemctl-list-jobs.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "locale-util.h"
+#include "systemctl-list-jobs.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const char *method, const char *prefix) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ const char *name, *type;
+ uint32_t other_id;
+ int r;
+
+ assert(bus);
+
+ r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
+
+ r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
+ _cleanup_free_ char *row = NULL;
+ int rc;
+
+ if (asprintf(&row, "%s %u (%s/%s)", prefix, other_id, name, type) < 0)
+ return log_oom();
+
+ rc = table_add_many(table,
+ TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
+ TABLE_STRING, row,
+ TABLE_EMPTY,
+ TABLE_EMPTY);
+ if (rc < 0)
+ return table_log_add_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);
+
+ return 0;
+}
+
+struct job_info {
+ uint32_t id;
+ const char *name, *type, *state;
+};
+
+static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
+ _cleanup_(table_unrefp) Table *table = NULL;
+ const struct job_info *j;
+ const char *on, *off;
+ int r;
+
+ assert(n == 0 || jobs);
+
+ if (n == 0) {
+ if (!arg_no_legend) {
+ on = ansi_highlight_green();
+ off = ansi_normal();
+
+ printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
+ }
+ return 0;
+ }
+
+ (void) pager_open(arg_pager_flags);
+
+ table = table_new("job", "unit", "type", "state");
+ if (!table)
+ return log_oom();
+
+ table_set_header(table, !arg_no_legend);
+ if (arg_full)
+ table_set_width(table, 0);
+
+ (void) table_set_empty_string(table, "-");
+
+ for (j = jobs; j < jobs + n; j++) {
+ if (streq(j->state, "running"))
+ on = ansi_highlight();
+ else
+ on = "";
+
+ r = table_add_many(table,
+ TABLE_UINT, j->id,
+ TABLE_STRING, j->name,
+ TABLE_SET_COLOR, on,
+ TABLE_STRING, j->type,
+ TABLE_STRING, j->state,
+ TABLE_SET_COLOR, on);
+ if (r < 0)
+ return table_log_add_error(r);
+
+ if (arg_jobs_after)
+ output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
+ if (arg_jobs_before)
+ output_waiting_jobs(bus, table, j->id, "GetJobBefore", "\tblocking job");
+ }
+
+ r = table_print(table, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to print the table: %m");
+
+ if (!arg_no_legend) {
+ on = ansi_highlight();
+ off = ansi_normal();
+
+ printf("\n%s%u jobs listed%s.\n", on, n, off);
+ }
+
+ return 0;
+}
+
+static bool output_show_job(struct job_info *job, char **patterns) {
+ return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
+}
+
+int list_jobs(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ struct job_info *jobs = NULL;
+ const char *name, *type, *state;
+ bool skipped = false;
+ size_t size = 0;
+ unsigned c = 0;
+ sd_bus *bus;
+ uint32_t id;
+ int r;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, NULL, NULL)) > 0) {
+ struct job_info job = { id, name, type, state };
+
+ if (!output_show_job(&job, strv_skip(argv, 1))) {
+ skipped = true;
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(jobs, size, c + 1))
+ return log_oom();
+
+ jobs[c++] = job;
+ }
+ 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);
+
+ (void) pager_open(arg_pager_flags);
+
+ return output_jobs_list(bus, jobs, c, skipped);
+}