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
1 changed files with 229 additions and 370 deletions

View File

@ -39,6 +39,7 @@
#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "fs-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) {
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;
unsigned n_shown = 0;
int job_count = 0;
bool full = arg_full || FLAGS_SET(arg_pager_flags, PAGER_DISABLE);
int r;
max_id_len = STRLEN("UNIT");
load_len = STRLEN("LOAD");
active_len = STRLEN("ACTIVE");
sub_len = STRLEN("SUB");
job_len = STRLEN("JOB");
max_desc_len = STRLEN("DESCRIPTION");
table = table_new("", "unit", "load", "active", "sub", "job", "description");
if (!table)
return log_oom();
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
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));
load_len = MAX(load_len, strlen(u->load_state));
active_len = MAX(active_len, strlen(u->active_state));
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;
_cleanup_free_ char *j = NULL;
const char *on_underline = "", *on_loaded = "", *on_active = "";
const char *on_circle = "", *id;
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 &&
!streq(unit_type_suffix(u->id), unit_type_suffix((u + 1)->id))) {
on_underline = ansi_underline();
off_underline = ansi_normal();
underline = true;
}
if (STR_IN_SET(u->load_state, "error", "not-found", "bad-setting", "masked") && !arg_plain) {
on_circle = ansi_highlight_yellow();
off_circle = ansi_normal();
circle = true;
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) {
on_circle = ansi_highlight_red();
off_circle = ansi_normal();
circle = true;
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) {
@ -516,36 +437,47 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
} else
id = u->id;
if (arg_full) {
e = ellipsize(id, id_len, 33);
if (!e)
return log_oom();
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
TABLE_SET_COLOR, on_circle,
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 (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 (u->job_id != 0)
job_count++;
}
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) {
const char *on, *off;
size_t records = table_get_rows(table) - 1;
if (n_shown) {
if (records > 0) {
puts("\n"
"LOAD = Reflects whether the unit definition was properly loaded.\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"))
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",
on, n_shown, off);
on, records, off);
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",
on, n_shown, off);
on, records, off);
else
printf("%u loaded units listed.\n", n_shown);
printf("%zu loaded units listed.\n", records);
}
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) {
_cleanup_(table_unrefp) Table *table = NULL;
struct socket_info *s;
unsigned pathlen = STRLEN("LISTEN"),
typelen = STRLEN("TYPE") * arg_show_types,
socklen = STRLEN("UNIT"),
servlen = STRLEN("ACTIVATES");
const char *on, *off;
int r;
for (s = socket_infos; s < socket_infos + cs; s++) {
unsigned tmp = 0;
char **a;
table = table_new("listen", "type", "units", "activates");
if (!table)
return log_oom();
socklen = MAX(socklen, strlen(s->id));
if (arg_show_types)
typelen = MAX(typelen, strlen(s->type));
pathlen = MAX(pathlen, strlen(s->path) + (s->machine ? strlen(s->machine)+1 : 0));
STRV_FOREACH(a, s->triggered)
tmp += strlen(*a) + 2*(a != s->triggered);
servlen = MAX(servlen, tmp);
if (!arg_show_types) {
/* Hide the second (TYPE) column */
r = table_set_display(table, 0, 2, 3, (size_t) -1);
if (r < 0)
return log_error_errno(r, "Failed to set columns to display: %m");
}
if (cs) {
if (!arg_no_legend)
printf("%-*s %-*.*s%-*s %s\n",
pathlen, "LISTEN",
typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
socklen, "UNIT",
"ACTIVATES");
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
if (cs) {
for (s = socket_infos; s < socket_infos + cs; s++) {
_cleanup_free_ char *j = NULL;
_cleanup_free_ char *j = NULL, *activates = NULL;
const char *path;
char **a;
if (s->machine) {
j = strjoin(s->machine, ":", s->path);
@ -1090,29 +1013,32 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
} else
path = s->path;
if (arg_show_types)
printf("%-*s %-*s %-*s",
pathlen, path, typelen, s->type, socklen, s->id);
else
printf("%-*s %-*s",
pathlen, path, socklen, s->id);
STRV_FOREACH(a, s->triggered)
printf("%s %s",
a == s->triggered ? "" : ",", *a);
printf("\n");
activates = strv_join(s->triggered, ", ");
if (!activates)
return log_oom();
r = table_add_many(table,
TABLE_STRING, path,
TABLE_STRING, s->type,
TABLE_STRING, s->id,
TABLE_STRING, activates);
if (r < 0)
return table_log_add_error(r);
}
on = ansi_highlight();
off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
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) {
printf("%s%u sockets listed.%s\n", on, cs, off);
printf("\n%s%u sockets listed.%s\n", on, cs, off);
if (!arg_all)
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) {
_cleanup_(table_unrefp) Table *table = NULL;
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;
int r;
assert(timer_infos || n == 0);
for (t = timer_infos; t < timer_infos + n; t++) {
unsigned ul = 0;
char **a;
table = table_new("next", "left", "last", "passed", "unit", "activates");
if (!table)
return log_oom();
if (t->next_elapse > 0) {
char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
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);
}
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 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++) {
_cleanup_free_ char *j = NULL;
_cleanup_free_ char *j = NULL, *activates = NULL;
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) {
j = strjoin(t->machine, ":", t->id);
@ -1379,26 +1257,34 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
} else
unit = t->id;
printf("%-*s %-*s %-*s %-*s %-*s",
nextlen, tstamp1, leftlen, trel1, lastlen, tstamp2, passedlen, trel2, unitlen, unit);
activates = strv_join(t->triggered, ", ");
if (!activates)
return log_oom();
STRV_FOREACH(a, t->triggered)
printf("%s %s",
a == t->triggered ? "" : ",", *a);
printf("\n");
r = table_add_many(table,
TABLE_TIMESTAMP, t->next_elapse,
TABLE_TIMESTAMP_RELATIVE, t->next_elapse,
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();
off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
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) {
printf("%s%u timers listed.%s\n", on, n, off);
printf("\n%s%u timers listed.%s\n", on, n, off);
if (!arg_all)
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;
}
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
unsigned max_id_len, id_cols, state_cols, preset_cols;
static int output_unit_file_list(const UnitFileList *units, unsigned c) {
_cleanup_(table_unrefp) Table *table = NULL;
const UnitFileList *u;
int r;
max_id_len = STRLEN("UNIT FILE");
state_cols = STRLEN("STATE");
preset_cols = STRLEN("VENDOR PRESET");
table = table_new("unit file", "state", "vendor preset");
if (!table)
return log_oom();
for (u = units; u < units + c; u++) {
max_id_len = MAX(max_id_len, strlen(basename(u->path)));
state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
}
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());
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (u = units; u < units + c; u++) {
const char *on_underline = NULL, *on_unit_color = NULL, *id;
const char *on_preset_color = NULL, *off_preset = NULL, *unit_preset_str;
_cleanup_free_ char *e = NULL;
int r;
const char *on_preset_color = NULL, *unit_preset_str;
bool underline;
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();
else if (u->state == UNIT_FILE_ENABLED)
on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
else
on_unit_color = on_underline;
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();
}
if (on_underline || on_preset_color)
off_preset = ansi_normal();
e = arg_full ? NULL : ellipsize(id, id_cols, 33);
printf("%s%-*s %s%-*s %s%-*s%s\n",
strempty(on_underline),
id_cols, e ? e : id,
strempty(on_unit_color), state_cols, unit_file_state_to_string(u->state),
strempty(on_preset_color), preset_cols, unit_preset_str, strempty(off_preset));
r = table_add_many(table,
TABLE_STRING, id,
TABLE_SET_COLOR, strempty(on_underline),
TABLE_STRING, unit_file_state_to_string(u->state),
TABLE_SET_COLOR, strempty(on_unit_color),
TABLE_STRING, unit_preset_str,
TABLE_SET_COLOR, strempty(on_preset_color));
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)
printf("\n%u unit files listed.\n", c);
return 0;
}
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);
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())
for (unit = units; unit < units + c; unit++)
@ -2081,94 +1956,77 @@ static int get_machine_list(
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;
unsigned
circle_len = 0,
namelen = STRLEN("NAME"),
statelen = STRLEN("STATE"),
failedlen = STRLEN("FAILED"),
jobslen = STRLEN("JOBS");
bool state_missing = false;
int r;
assert(machine_infos || n == 0);
for (m = machine_infos; m < machine_infos + n; m++) {
namelen = MAX(namelen,
strlen(m->name) + (m->is_host ? STRLEN(" (host)") : 0));
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));
table = table_new("", "name", "state", "failed", "jobs");
if (!table)
return log_oom();
if (!arg_plain && m->state && !streq(m->state, "running"))
circle_len = 2;
}
if (!arg_no_legend) {
if (circle_len > 0)
fputs(" ", stdout);
printf("%-*s %-*s %-*s %-*s\n",
namelen, "NAME",
statelen, "STATE",
failedlen, "FAILED",
jobslen, "JOBS");
}
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
for (m = machine_infos; m < machine_infos + n; m++) {
const char *on_state = "", *off_state = "";
const char *on_failed = "", *off_failed = "";
_cleanup_free_ char *mname = NULL;
const char *on_state = "", *on_failed = "";
bool circle = false;
if (streq_ptr(m->state, "degraded")) {
on_state = ansi_highlight_red();
off_state = ansi_normal();
circle = true;
} else if (!streq_ptr(m->state, "running")) {
on_state = ansi_highlight_yellow();
off_state = ansi_normal();
circle = true;
}
if (m->n_failed_units > 0) {
if (m->n_failed_units > 0)
on_failed = ansi_highlight_red();
off_failed = ansi_normal();
} else
on_failed = off_failed = "";
if (circle_len > 0)
printf("%s%s%s ", on_state, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ", off_state);
else
on_failed = "";
if (!m->state)
state_missing = true;
if (m->is_host)
printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
(int) (namelen - strlen(" (host)")),
strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
else
printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
namelen, strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
mname = strjoin(strna(m->name), " (host)");
r = table_add_many(table,
TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
TABLE_SET_COLOR, on_state,
TABLE_STRING, m->is_host ? mname : strna(m->name),
TABLE_STRING, strna(m->state),
TABLE_SET_COLOR, on_state,
TABLE_UINT32, m->n_failed_units,
TABLE_SET_COLOR, on_failed,
TABLE_UINT32, 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) {
printf("\n");
if (state_missing && geteuid() != 0)
printf("Notice: some information only available to privileged users was not shown.\n");
printf("%u machines listed.\n", n);
}
return 0;
}
static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL;
sd_bus *bus;
int r;
int r, rc;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@ -2181,10 +2039,10 @@ static int list_machines(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
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);
return 0;
return rc;
}
static int get_default(int argc, char *argv[], void *userdata) {
@ -2292,7 +2150,7 @@ finish:
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_message_unrefp) sd_bus_message *reply = NULL;
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)
return bus_log_parse_error(r);
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);
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);
@ -2334,11 +2206,11 @@ struct job_info {
const char *name, *type, *state;
};
static void output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) {
unsigned id_len, unit_len, type_len, state_len;
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;
bool shorten = false;
int r;
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);
}
return;
return 0;
}
(void) pager_open(arg_pager_flags);
id_len = STRLEN("JOB");
unit_len = STRLEN("UNIT");
type_len = STRLEN("TYPE");
state_len = STRLEN("STATE");
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);
for (j = jobs; j < jobs + n; j++) {
uint32_t id = j->id;
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")) {
if (streq(j->state, "running"))
on = ansi_highlight();
off = ansi_normal();
} else
on = off = "";
else
on = "";
e = shorten ? ellipsize(j->name, unit_len, 33) : NULL;
printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
id_len, j->id,
on, unit_len, e ? e : j->name, off,
type_len, j->type,
on, state_len, j->state, off);
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, j->id, "GetJobAfter", "\twaiting for job");
output_waiting_jobs(bus, table, j->id, "GetJobAfter", "\twaiting for job");
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) {
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) {
@ -2469,8 +2329,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
output_jobs_list(bus, jobs, c, skipped);
return 0;
return output_jobs_list(bus, jobs, c, skipped);
}
static int cancel_job(int argc, char *argv[], void *userdata) {