]> git.proxmox.com Git - systemd.git/blob - src/systemctl/systemctl-list-jobs.c
New upstream version 249~rc1
[systemd.git] / src / systemctl / systemctl-list-jobs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "bus-error.h"
4 #include "bus-locator.h"
5 #include "locale-util.h"
6 #include "systemctl-list-jobs.h"
7 #include "systemctl-util.h"
8 #include "systemctl.h"
9 #include "terminal-util.h"
10
11 static int output_waiting_jobs(sd_bus *bus, Table *table, uint32_t id, const char *method, const char *prefix) {
12 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
13 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
14 const char *name, *type;
15 uint32_t other_id;
16 int r;
17
18 assert(bus);
19
20 r = bus_call_method(bus, bus_systemd_mgr, method, &error, &reply, "u", id);
21 if (r < 0)
22 return log_debug_errno(r, "Failed to get waiting jobs for job %" PRIu32, id);
23
24 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
25 if (r < 0)
26 return bus_log_parse_error(r);
27
28 while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
29 _cleanup_free_ char *row = NULL;
30 int rc;
31
32 if (asprintf(&row, "%s %u (%s/%s)", prefix, other_id, name, type) < 0)
33 return log_oom();
34
35 rc = table_add_many(table,
36 TABLE_STRING, special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
37 TABLE_STRING, row,
38 TABLE_EMPTY,
39 TABLE_EMPTY);
40 if (rc < 0)
41 return table_log_add_error(r);
42 }
43
44 if (r < 0)
45 return bus_log_parse_error(r);
46
47 r = sd_bus_message_exit_container(reply);
48 if (r < 0)
49 return bus_log_parse_error(r);
50
51 return 0;
52 }
53
54 struct job_info {
55 uint32_t id;
56 const char *name, *type, *state;
57 };
58
59 static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
60 _cleanup_(table_unrefp) Table *table = NULL;
61 const char *on, *off;
62 int r;
63
64 assert(n == 0 || jobs);
65
66 if (n == 0) {
67 if (arg_legend != 0) {
68 on = ansi_highlight_green();
69 off = ansi_normal();
70
71 printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
72 }
73 return 0;
74 }
75
76 (void) pager_open(arg_pager_flags);
77
78 table = table_new("job", "unit", "type", "state");
79 if (!table)
80 return log_oom();
81
82 table_set_header(table, arg_legend != 0);
83 if (arg_full)
84 table_set_width(table, 0);
85
86 (void) table_set_empty_string(table, "-");
87
88 for (const struct job_info *j = jobs; j < jobs + n; j++) {
89 if (streq(j->state, "running"))
90 on = ansi_highlight();
91 else
92 on = "";
93
94 r = table_add_many(table,
95 TABLE_UINT, j->id,
96 TABLE_STRING, j->name,
97 TABLE_SET_COLOR, on,
98 TABLE_STRING, j->type,
99 TABLE_STRING, j->state,
100 TABLE_SET_COLOR, on);
101 if (r < 0)
102 return table_log_add_error(r);
103
104 if (arg_jobs_after)
105 output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
106 if (arg_jobs_before)
107 output_waiting_jobs(bus, table, j->id, "GetJobBefore", "\tblocking job");
108 }
109
110 r = table_print(table, NULL);
111 if (r < 0)
112 return log_error_errno(r, "Failed to print the table: %m");
113
114 if (arg_legend != 0) {
115 on = ansi_highlight();
116 off = ansi_normal();
117
118 printf("\n%s%u jobs listed%s.\n", on, n, off);
119 }
120
121 return 0;
122 }
123
124 static bool output_show_job(struct job_info *job, char **patterns) {
125 return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
126 }
127
128 int list_jobs(int argc, char *argv[], void *userdata) {
129 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
130 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
131 _cleanup_free_ struct job_info *jobs = NULL;
132 const char *name, *type, *state;
133 bool skipped = false;
134 unsigned c = 0;
135 sd_bus *bus;
136 uint32_t id;
137 int r;
138
139 r = acquire_bus(BUS_MANAGER, &bus);
140 if (r < 0)
141 return r;
142
143 r = bus_call_method(bus, bus_systemd_mgr, "ListJobs", &error, &reply, NULL);
144 if (r < 0)
145 return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
146
147 r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
148 if (r < 0)
149 return bus_log_parse_error(r);
150
151 while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, NULL, NULL)) > 0) {
152 struct job_info job = { id, name, type, state };
153
154 if (!output_show_job(&job, strv_skip(argv, 1))) {
155 skipped = true;
156 continue;
157 }
158
159 if (!GREEDY_REALLOC(jobs, c + 1))
160 return log_oom();
161
162 jobs[c++] = job;
163 }
164 if (r < 0)
165 return bus_log_parse_error(r);
166
167 r = sd_bus_message_exit_container(reply);
168 if (r < 0)
169 return bus_log_parse_error(r);
170
171 (void) pager_open(arg_pager_flags);
172
173 return output_jobs_list(bus, jobs, c, skipped);
174 }