1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-02 02:21:44 +03:00

systemctl: use format-table.[ch] for tables

This commit is contained in:
Frantisek Sumsal 2020-01-03 13:01:26 +01:00 committed by Zbigniew Jędrzejewski-Szmek
parent 7c286cd6a6
commit de9a8fe18e

View File

@ -39,6 +39,7 @@
#include "exec-util.h" #include "exec-util.h"
#include "exit-status.h" #include "exit-status.h"
#include "fd-util.h" #include "fd-util.h"
#include "format-table.h"
#include "format-util.h" #include "format-util.h"
#include "fs-util.h" #include "fs-util.h"
#include "glob-util.h" #include "glob-util.h"
@ -389,122 +390,42 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
} }
static int output_units_list(const UnitInfo *unit_infos, unsigned c) { static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
unsigned circle_len = 0, id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len, max_desc_len; _cleanup_(table_unrefp) Table *table = NULL;
const UnitInfo *u; const UnitInfo *u;
unsigned n_shown = 0;
int job_count = 0; int job_count = 0;
bool full = arg_full || FLAGS_SET(arg_pager_flags, PAGER_DISABLE); int r;
max_id_len = STRLEN("UNIT"); table = table_new("", "unit", "load", "active", "sub", "job", "description");
load_len = STRLEN("LOAD"); if (!table)
active_len = STRLEN("ACTIVE"); return log_oom();
sub_len = STRLEN("SUB");
job_len = STRLEN("JOB"); table_set_header(table, !arg_no_legend);
max_desc_len = STRLEN("DESCRIPTION"); if (arg_full)
table_set_width(table, 0);
for (u = unit_infos; u < unit_infos + c; u++) { for (u = unit_infos; u < unit_infos + c; u++) {
max_id_len = MAX(max_id_len, strlen(u->id) + (u->machine ? strlen(u->machine)+1 : 0)); _cleanup_free_ char *j = NULL;
load_len = MAX(load_len, strlen(u->load_state)); const char *on_underline = "", *on_loaded = "", *on_active = "";
active_len = MAX(active_len, strlen(u->active_state)); const char *on_circle = "", *id;
sub_len = MAX(sub_len, strlen(u->sub_state));
max_desc_len = MAX(max_desc_len, strlen(u->description));
if (u->job_id != 0) {
job_len = MAX(job_len, strlen(u->job_type));
job_count++;
}
if (!arg_no_legend &&
(streq(u->active_state, "failed") ||
STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked")))
circle_len = 2;
}
if (!arg_full && original_stdout_is_tty) {
unsigned basic_len;
id_len = MIN(max_id_len, 25u); /* as much as it needs, but at most 25 for now */
basic_len = circle_len + 1 + id_len + 1 + load_len + 1 + active_len + 1 + sub_len + 1;
if (job_count)
basic_len += job_len + 1;
if (basic_len < (unsigned) columns()) {
unsigned extra_len, incr;
extra_len = columns() - basic_len;
/* Either UNIT already got 25, or is fully satisfied.
* Grant up to 25 to DESC now. */
incr = MIN(extra_len, 25u);
desc_len = incr;
extra_len -= incr;
/* Of the remainder give as much as the ID needs to the ID, and give the rest to the
* description but not more than it needs. */
if (extra_len > 0) {
incr = MIN(max_id_len - id_len, extra_len);
id_len += incr;
desc_len += MIN(extra_len - incr, max_desc_len - desc_len);
}
} else
desc_len = 0;
} else {
id_len = max_id_len;
desc_len = max_desc_len;
}
for (u = unit_infos; u < unit_infos + c; u++) {
_cleanup_free_ char *e = NULL, *j = NULL;
const char *on_underline = "", *off_underline = "";
const char *on_loaded = "", *off_loaded = "";
const char *on_active = "", *off_active = "";
const char *on_circle = "", *off_circle = "";
const char *id;
bool circle = false, underline = false; bool circle = false, underline = false;
if (!n_shown && !arg_no_legend) {
if (circle_len > 0)
fputs(" ", stdout);
printf("%s%-*s %-*s %-*s %-*s ",
ansi_underline(),
id_len, "UNIT",
load_len, "LOAD",
active_len, "ACTIVE",
sub_len, "SUB");
if (job_count)
printf("%-*s ", job_len, "JOB");
printf("%-*.*s%s\n",
desc_len,
full ? -1 : (int) desc_len,
"DESCRIPTION",
ansi_normal());
}
n_shown++;
if (u + 1 < unit_infos + c && if (u + 1 < unit_infos + c &&
!streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) { !streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
on_underline = ansi_underline(); on_underline = ansi_underline();
off_underline = ansi_normal();
underline = true; underline = true;
} }
if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) { if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
on_circle = ansi_highlight_yellow(); on_circle = ansi_highlight_yellow();
off_circle = ansi_normal();
circle = true; circle = true;
on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red(); on_loaded = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
off_loaded = underline ? on_underline : ansi_normal();
} else if (streq(u->active_state, "failed") && !arg_plain) { } else if (streq(u->active_state, "failed") && !arg_plain) {
on_circle = ansi_highlight_red(); on_circle = ansi_highlight_red();
off_circle = ansi_normal();
circle = true; circle = true;
on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red(); on_active = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
off_active = underline ? on_underline : ansi_normal(); } else {
on_active = on_underline;
on_loaded = on_underline;
} }
if (u->machine) { if (u->machine) {
@ -516,36 +437,47 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
} else } else
id = u->id; id = u->id;
if (arg_full) { r = table_add_many(table,
e = ellipsize(id, id_len, 33); TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
if (!e) TABLE_SET_COLOR, on_circle,
return log_oom(); TABLE_STRING, id,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->load_state,
TABLE_SET_COLOR, on_loaded,
TABLE_STRING, u->active_state,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->sub_state,
TABLE_SET_COLOR, on_active,
TABLE_STRING, u->job_id ? u->job_type: "",
TABLE_SET_COLOR, u->job_id ? on_underline : "",
TABLE_STRING, u->description,
TABLE_SET_COLOR, on_underline);
if (r < 0)
return table_log_add_error(r);
id = e; if (u->job_id != 0)
} job_count++;
if (circle_len > 0)
printf("%s%s%s ", on_circle, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_circle);
printf("%s%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
on_underline,
on_active, id_len, id, off_active,
on_loaded, load_len, u->load_state, off_loaded,
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 : "");
printf("%-*.*s%s\n",
desc_len,
full ? -1 : (int) desc_len,
u->description,
off_underline);
} }
if (job_count == 0) {
/* There's no data in the JOB column, so let's hide it */
/* Also, convert all number constants to size_t so va_arg()
* in table_set_display() fetches a correct number of bytes from
* the stack */
r = table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 6, (size_t) -1);
if (r < 0)
return log_error_errno(r, "Failed to set columns to display: %m");
}
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) { if (!arg_no_legend) {
const char *on, *off; const char *on, *off;
size_t records = table_get_rows(table) - 1;
if (n_shown) { if (records > 0) {
puts("\n" puts("\n"
"LOAD = Reflects whether the unit definition was properly loaded.\n" "LOAD = Reflects whether the unit definition was properly loaded.\n"
"ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n" "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
@ -559,15 +491,15 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
} }
if (arg_all || strv_contains(arg_states, "inactive")) if (arg_all || strv_contains(arg_states, "inactive"))
printf("%s%u loaded units listed.%s\n" printf("%s%zu loaded units listed.%s\n"
"To show all installed unit files use 'systemctl list-unit-files'.\n", "To show all installed unit files use 'systemctl list-unit-files'.\n",
on, n_shown, off); on, records, off);
else if (!arg_states) else if (!arg_states)
printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n" printf("%s%zu loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
"To show all installed unit files use 'systemctl list-unit-files'.\n", "To show all installed unit files use 'systemctl list-unit-files'.\n",
on, n_shown, off); on, records, off);
else else
printf("%u loaded units listed.\n", n_shown); printf("%zu loaded units listed.\n", records);
} }
return 0; return 0;
@ -1048,39 +980,30 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_
} }
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
_cleanup_(table_unrefp) Table *table = NULL;
struct socket_info *s; struct socket_info *s;
unsigned pathlen = STRLEN("LISTEN"),
typelen = STRLEN("TYPE") * arg_show_types,
socklen = STRLEN("UNIT"),
servlen = STRLEN("ACTIVATES");
const char *on, *off; const char *on, *off;
int r;
for (s = socket_infos; s < socket_infos + cs; s++) { table = table_new("listen", "type", "units", "activates");
unsigned tmp = 0; if (!table)
char **a; return log_oom();
socklen = MAX(socklen, strlen(s->id)); if (!arg_show_types) {
if (arg_show_types) /* Hide the second (TYPE) column */
typelen = MAX(typelen, strlen(s->type)); r = table_set_display(table, 0, 2, 3, (size_t) -1);
pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0)); if (r < 0)
return log_error_errno(r, "Failed to set columns to display: %m");
STRV_FOREACH(a, s->triggered)
tmp += strlen(*a) + 2*(a != s->triggered);
servlen = MAX(servlen, tmp);
} }
if (cs) { table_set_header(table, !arg_no_legend);
if (!arg_no_legend) if (arg_full)
printf("%-*s %-*.*s%-*s %s\n", table_set_width(table, 0);
pathlen, "LISTEN",
typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
socklen, "UNIT",
"ACTIVATES");
if (cs) {
for (s = socket_infos; s < socket_infos + cs; s++) { for (s = socket_infos; s < socket_infos + cs; s++) {
_cleanup_free_ char *j = NULL; _cleanup_free_ char *j = NULL, *activates = NULL;
const char *path; const char *path;
char **a;
if (s->machine) { if (s->machine) {
j = strjoin(s->machine, ":", s->path); j = strjoin(s->machine, ":", s->path);
@ -1090,29 +1013,32 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
} else } else
path = s->path; path = s->path;
if (arg_show_types) activates = strv_join(s->triggered, ", ");
printf("%-*s %-*s %-*s", if (!activates)
pathlen, path, typelen, s->type, socklen, s->id); return log_oom();
else
printf("%-*s %-*s", r = table_add_many(table,
pathlen, path, socklen, s->id); TABLE_STRING, path,
STRV_FOREACH(a, s->triggered) TABLE_STRING, s->type,
printf("%s %s", TABLE_STRING, s->id,
a == s->triggered ? "" : ",", *a); TABLE_STRING, activates);
printf("\n"); if (r < 0)
return table_log_add_error(r);
} }
on = ansi_highlight(); on = ansi_highlight();
off = ansi_normal(); off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else { } else {
on = ansi_highlight_red(); on = ansi_highlight_red();
off = ansi_normal(); off = ansi_normal();
} }
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) { if (!arg_no_legend) {
printf("%s%u sockets listed.%s\n", on, cs, off); printf("\n%s%u sockets listed.%s\n", on, cs, off);
if (!arg_all) if (!arg_all)
printf("Pass --all to see loaded but inactive sockets, too.\n"); printf("Pass --all to see loaded but inactive sockets, too.\n");
} }
@ -1303,73 +1229,25 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf
} }
static int output_timers_list(struct timer_info *timer_infos, unsigned n) { static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
_cleanup_(table_unrefp) Table *table = NULL;
struct timer_info *t; struct timer_info *t;
unsigned
nextlen = STRLEN("NEXT"),
leftlen = STRLEN("LEFT"),
lastlen = STRLEN("LAST"),
passedlen = STRLEN("PASSED"),
unitlen = STRLEN("UNIT"),
activatelen = STRLEN("ACTIVATES");
const char *on, *off; const char *on, *off;
int r;
assert(timer_infos || n == 0); assert(timer_infos || n == 0);
for (t = timer_infos; t < timer_infos + n; t++) { table = table_new("next", "left", "last", "passed", "unit", "activates");
unsigned ul = 0; if (!table)
char **a; return log_oom();
if (t->next_elapse > 0) { table_set_header(table, !arg_no_legend);
char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = ""; if (arg_full)
table_set_width(table, 0);
format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
nextlen = MAX(nextlen, strlen(tstamp) + 1);
format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
leftlen = MAX(leftlen, strlen(trel));
}
if (t->last_trigger > 0) {
char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
format_timestamp(tstamp, sizeof(tstamp), t->last_trigger);
lastlen = MAX(lastlen, strlen(tstamp) + 1);
format_timestamp_relative(trel, sizeof(trel), t->last_trigger);
passedlen = MAX(passedlen, strlen(trel));
}
unitlen = MAX(unitlen, strlen(t->id) + (t->machine ? strlen(t->machine)+1 : 0));
STRV_FOREACH(a, t->triggered)
ul += strlen(*a) + 2*(a != t->triggered);
activatelen = MAX(activatelen, ul);
}
if (n > 0) { if (n > 0) {
if (!arg_no_legend)
printf("%-*s %-*s %-*s %-*s %-*s %s\n",
nextlen, "NEXT",
leftlen, "LEFT",
lastlen, "LAST",
passedlen, "PASSED",
unitlen, "UNIT",
"ACTIVATES");
for (t = timer_infos; t < timer_infos + n; t++) { for (t = timer_infos; t < timer_infos + n; t++) {
_cleanup_free_ char *j = NULL; _cleanup_free_ char *j = NULL, *activates = NULL;
const char *unit; const char *unit;
char tstamp1[FORMAT_TIMESTAMP_MAX] = "n/a", trel1[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
char tstamp2[FORMAT_TIMESTAMP_MAX] = "n/a", trel2[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
char **a;
format_timestamp(tstamp1, sizeof(tstamp1), t->next_elapse);
format_timestamp_relative(trel1, sizeof(trel1), t->next_elapse);
format_timestamp(tstamp2, sizeof(tstamp2), t->last_trigger);
format_timestamp_relative(trel2, sizeof(trel2), t->last_trigger);
if (t->machine) { if (t->machine) {
j = strjoin(t->machine, ":", t->id); j = strjoin(t->machine, ":", t->id);
@ -1379,26 +1257,34 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
} else } else
unit = t->id; unit = t->id;
printf("%-*s %-*s %-*s %-*s %-*s", activates = strv_join(t->triggered, ", ");
nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit); if (!activates)
return log_oom();
STRV_FOREACH(a, t->triggered) r = table_add_many(table,
printf("%s %s", TABLE_TIMESTAMP, t->next_elapse,
a == t->triggered ? "" : ",", *a); TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
printf("\n"); TABLE_TIMESTAMP, t->last_trigger,
TABLE_TIMESTAMP_RELATIVE, t->last_trigger,
TABLE_STRING, unit,
TABLE_STRING, activates);
if (r < 0)
return table_log_add_error(r);
} }
on = ansi_highlight(); on = ansi_highlight();
off = ansi_normal(); off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else { } else {
on = ansi_highlight_red(); on = ansi_highlight_red();
off = ansi_normal(); off = ansi_normal();
} }
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) { if (!arg_no_legend) {
printf("%s%u timers listed.%s\n", on, n, off); printf("\n%s%u timers listed.%s\n", on, n, off);
if (!arg_all) if (!arg_all)
printf("Pass --all to see loaded but inactive timers, too.\n"); printf("Pass --all to see loaded but inactive timers, too.\n");
} }
@ -1549,42 +1435,22 @@ static bool output_show_unit_file(const UnitFileList *u, char **states, char **p
return true; return true;
} }
static void output_unit_file_list(const UnitFileList *units, unsigned c) { static int output_unit_file_list(const UnitFileList *units, unsigned c) {
unsigned max_id_len, id_cols, state_cols, preset_cols; _cleanup_(table_unrefp) Table *table = NULL;
const UnitFileList *u; const UnitFileList *u;
int r;
max_id_len = STRLEN("UNIT FILE"); table = table_new("unit file", "state", "vendor preset");
state_cols = STRLEN("STATE"); if (!table)
preset_cols = STRLEN("VENDOR PRESET"); return log_oom();
for (u = units; u < units + c; u++) { table_set_header(table, !arg_no_legend);
max_id_len = MAX(max_id_len, strlen(basename(u->path))); if (arg_full)
state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state))); table_set_width(table, 0);
}
if (!arg_full) {
unsigned basic_cols;
id_cols = MIN(max_id_len, 25u);
basic_cols = 1 + id_cols + state_cols;
if (basic_cols < (unsigned) columns())
id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
} else
id_cols = max_id_len;
if (!arg_no_legend && c > 0)
printf("%s%-*s %-*s %-*s%s\n",
ansi_underline(),
id_cols, "UNIT FILE",
state_cols, "STATE",
preset_cols, "VENDOR PRESET",
ansi_normal());
for (u = units; u < units + c; u++) { for (u = units; u < units + c; u++) {
const char *on_underline = NULL, *on_unit_color = NULL, *id; const char *on_underline = NULL, *on_unit_color = NULL, *id;
const char *on_preset_color = NULL, *off_preset = NULL, *unit_preset_str; const char *on_preset_color = NULL, *unit_preset_str;
_cleanup_free_ char *e = NULL;
int r;
bool underline; bool underline;
underline = u + 1 < units + c && underline = u + 1 < units + c &&
@ -1601,6 +1467,8 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red(); on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
else if (u->state == UNIT_FILE_ENABLED) else if (u->state == UNIT_FILE_ENABLED)
on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green(); on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
else
on_unit_color = on_underline;
id = basename(u->path); id = basename(u->path);
@ -1616,20 +1484,25 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green(); on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
} }
if (on_underline || on_preset_color) r = table_add_many(table,
off_preset = ansi_normal(); TABLE_STRING, id,
TABLE_SET_COLOR, strempty(on_underline),
e = arg_full ? NULL : ellipsize(id, id_cols, 33); TABLE_STRING, unit_file_state_to_string(u->state),
TABLE_SET_COLOR, strempty(on_unit_color),
printf("%s%-*s %s%-*s %s%-*s%s\n", TABLE_STRING, unit_preset_str,
strempty(on_underline), TABLE_SET_COLOR, strempty(on_preset_color));
id_cols, e ? e : id, if (r < 0)
strempty(on_unit_color), state_cols, unit_file_state_to_string(u->state), return table_log_add_error(r);
strempty(on_preset_color), preset_cols, unit_preset_str, strempty(off_preset));
} }
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) if (!arg_no_legend)
printf("\n%u unit files listed.\n", c); printf("\n%u unit files listed.\n", c);
return 0;
} }
static int list_unit_files(int argc, char *argv[], void *userdata) { static int list_unit_files(int argc, char *argv[], void *userdata) {
@ -1772,7 +1645,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags); (void) pager_open(arg_pager_flags);
typesafe_qsort(units, c, compare_unit_file_list); typesafe_qsort(units, c, compare_unit_file_list);
output_unit_file_list(units, c); r = output_unit_file_list(units, c);
if (r < 0)
return r;
if (install_client_side()) if (install_client_side())
for (unit = units; unit < units + c; unit++) for (unit = units; unit < units + c; unit++)
@ -2081,94 +1956,77 @@ static int get_machine_list(
return c; return c;
} }
static void output_machines_list(struct machine_info *machine_infos, unsigned n) { static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
_cleanup_(table_unrefp) Table *table = NULL;
struct machine_info *m; struct machine_info *m;
unsigned
circle_len = 0,
namelen = STRLEN("NAME"),
statelen = STRLEN("STATE"),
failedlen = STRLEN("FAILED"),
jobslen = STRLEN("JOBS");
bool state_missing = false; bool state_missing = false;
int r;
assert(machine_infos || n == 0); assert(machine_infos || n == 0);
for (m = machine_infos; m < machine_infos + n; m++) { table = table_new("", "name", "state", "failed", "jobs");
namelen = MAX(namelen, if (!table)
strlen(m->name) + (m->is_host ? STRLEN(" (host)") : 0)); return log_oom();
statelen = MAX(statelen, strlen_ptr(m->state));
failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
if (!arg_plain && m->state && !streq(m->state, "running")) table_set_header(table, !arg_no_legend);
circle_len = 2; if (arg_full)
} table_set_width(table, 0);
if (!arg_no_legend) {
if (circle_len > 0)
fputs(" ", stdout);
printf("%-*s %-*s %-*s %-*s\n",
namelen, "NAME",
statelen, "STATE",
failedlen, "FAILED",
jobslen, "JOBS");
}
for (m = machine_infos; m < machine_infos + n; m++) { for (m = machine_infos; m < machine_infos + n; m++) {
const char *on_state = "", *off_state = ""; _cleanup_free_ char *mname = NULL;
const char *on_failed = "", *off_failed = ""; const char *on_state = "", *on_failed = "";
bool circle = false; bool circle = false;
if (streq_ptr(m->state, "degraded")) { if (streq_ptr(m->state, "degraded")) {
on_state = ansi_highlight_red(); on_state = ansi_highlight_red();
off_state = ansi_normal();
circle = true; circle = true;
} else if (!streq_ptr(m->state, "running")) { } else if (!streq_ptr(m->state, "running")) {
on_state = ansi_highlight_yellow(); on_state = ansi_highlight_yellow();
off_state = ansi_normal();
circle = true; circle = true;
} }
if (m->n_failed_units > 0) { if (m->n_failed_units > 0)
on_failed = ansi_highlight_red(); on_failed = ansi_highlight_red();
off_failed = ansi_normal(); else
} else on_failed = "";
on_failed = off_failed = "";
if (circle_len > 0)
printf("%s%s%s ", on_state, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_state);
if (!m->state) if (!m->state)
state_missing = true; state_missing = true;
if (m->is_host) if (m->is_host)
printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", mname = strjoin(strna(m->name), " (host)");
(int) (namelen - strlen(" (host)")),
strna(m->name), r = table_add_many(table,
on_state, statelen, strna(m->state), off_state, TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
on_failed, failedlen, m->n_failed_units, off_failed, TABLE_SET_COLOR, on_state,
jobslen, m->n_jobs); TABLE_STRING, m->is_host ? mname : strna(m->name),
else TABLE_STRING, strna(m->state),
printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n", TABLE_SET_COLOR, on_state,
namelen, strna(m->name), TABLE_UINT32, m->n_failed_units,
on_state, statelen, strna(m->state), off_state, TABLE_SET_COLOR, on_failed,
on_failed, failedlen, m->n_failed_units, off_failed, TABLE_UINT32, m->n_jobs);
jobslen, m->n_jobs); if (r < 0)
return table_log_add_error(r);
} }
r = table_print(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to print the table: %m");
if (!arg_no_legend) { if (!arg_no_legend) {
printf("\n"); printf("\n");
if (state_missing && geteuid() != 0) if (state_missing && geteuid() != 0)
printf("Notice: some information only available to privileged users was not shown.\n"); printf("Notice: some information only available to privileged users was not shown.\n");
printf("%u machines listed.\n", n); printf("%u machines listed.\n", n);
} }
return 0;
} }
static int list_machines(int argc, char *argv[], void *userdata) { static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL; struct machine_info *machine_infos = NULL;
sd_bus *bus; sd_bus *bus;
int r; int r, rc;
r = acquire_bus(BUS_MANAGER, &bus); r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0) if (r < 0)
@ -2181,10 +2039,10 @@ static int list_machines(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags); (void) pager_open(arg_pager_flags);
typesafe_qsort(machine_infos, r, compare_machine_info); typesafe_qsort(machine_infos, r, compare_machine_info);
output_machines_list(machine_infos, r); rc = output_machines_list(machine_infos, r);
free_machines_list(machine_infos, r); free_machines_list(machine_infos, r);
return 0; return rc;
} }
static int get_default(int argc, char *argv[], void *userdata) { static int get_default(int argc, char *argv[], void *userdata) {
@ -2292,7 +2150,7 @@ finish:
return r; return r;
} }
static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, const char *prefix) { 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_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *name, *type; const char *name, *type;
@ -2317,8 +2175,22 @@ static int output_waiting_jobs(sd_bus *bus, uint32_t id, const char *method, con
if (r < 0) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) while ((r = sd_bus_message_read(reply, "(usssoo)", &other_id, &name, &type, NULL, NULL, NULL)) > 0) {
printf("%s %u (%s/%s)\n", prefix, other_id, name, type); _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) if (r < 0)
return bus_log_parse_error(r); return bus_log_parse_error(r);
@ -2334,11 +2206,11 @@ struct job_info {
const char *name, *type, *state; const char *name, *type, *state;
}; };
static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) { static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
unsigned id_len, unit_len, type_len, state_len; _cleanup_(table_unrefp) Table *table = NULL;
const struct job_info *j; const struct job_info *j;
const char *on, *off; const char *on, *off;
bool shorten = false; int r;
assert(n == 0 || jobs); assert(n == 0 || jobs);
@ -2349,66 +2221,54 @@ static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned
printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off); printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
} }
return; return 0;
} }
(void) pager_open(arg_pager_flags); (void) pager_open(arg_pager_flags);
id_len = STRLEN("JOB"); table = table_new("job", "unit", "type", "state");
unit_len = STRLEN("UNIT"); if (!table)
type_len = STRLEN("TYPE"); return log_oom();
state_len = STRLEN("STATE");
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (j = jobs; j < jobs + n; j++) { for (j = jobs; j < jobs + n; j++) {
uint32_t id = j->id; if (streq(j->state, "running"))
assert(j->name && j->type && j->state);
id_len = MAX(id_len, DECIMAL_STR_WIDTH(id));
unit_len = MAX(unit_len, strlen(j->name));
type_len = MAX(type_len, strlen(j->type));
state_len = MAX(state_len, strlen(j->state));
}
if (!arg_full && id_len + 1 + unit_len + type_len + 1 + state_len > columns()) {
unit_len = MAX(33u, columns() - id_len - type_len - state_len - 3);
shorten = true;
}
if (!arg_no_legend)
printf("%*s %-*s %-*s %-*s\n",
id_len, "JOB",
unit_len, "UNIT",
type_len, "TYPE",
state_len, "STATE");
for (j = jobs; j < jobs + n; j++) {
_cleanup_free_ char *e = NULL;
if (streq(j->state, "running")) {
on = ansi_highlight(); on = ansi_highlight();
off = ansi_normal(); else
} else on = "";
on = off = "";
e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
printf("%*u %s%-*s%s %-*s %s%-*s%s\n", r = table_add_many(table,
id_len, j->id, TABLE_UINT, j->id,
on, unit_len, e ? e : j->name, off, TABLE_STRING, j->name,
type_len, j->type, TABLE_SET_COLOR, on,
on, state_len, j->state, off); 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) if (arg_jobs_after)
output_waiting_jobs(bus, j->id, "GetJobAfter", "\twaiting for job"); output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
if (arg_jobs_before) if (arg_jobs_before)
output_waiting_jobs(bus, j->id, "GetJobBefore", "\tblocking job"); 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) { if (!arg_no_legend) {
on = ansi_highlight(); on = ansi_highlight();
off = ansi_normal(); off = ansi_normal();
printf("\n%s%u jobs listed%s.\n", on, n, off); printf("\n%s%u jobs listed%s.\n", on, n, off);
} }
return 0;
} }
static bool output_show_job(struct job_info *job, char **patterns) { static bool output_show_job(struct job_info *job, char **patterns) {
@ -2469,8 +2329,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags); (void) pager_open(arg_pager_flags);
output_jobs_list(bus, jobs, c, skipped); return output_jobs_list(bus, jobs, c, skipped);
return 0;
} }
static int cancel_job(int argc, char *argv[], void *userdata) { static int cancel_job(int argc, char *argv[], void *userdata) {