diff options
Diffstat (limited to 'src/login/loginctl.c')
-rw-r--r-- | src/login/loginctl.c | 222 |
1 files changed, 153 insertions, 69 deletions
diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 7fc6efc..cf3bff4 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -44,6 +44,7 @@ static BusPrintPropertyFlags arg_print_flags = 0; static bool arg_full = false; static PagerFlags arg_pager_flags = 0; static bool arg_legend = true; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static const char *arg_kill_whom = NULL; static int arg_signal = SIGTERM; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; @@ -113,80 +114,115 @@ static OutputFlags get_output_flags(void) { colors_enabled() * OUTPUT_COLOR; } -static int show_table(Table *table, const char *word) { +static int list_table_print(Table *table, const char *type) { int r; assert(table); - assert(word); + assert(type); - if (table_get_rows(table) > 1 || OUTPUT_MODE_IS_JSON(arg_output)) { - r = table_set_sort(table, (size_t) 0); - if (r < 0) - return table_log_sort_error(r); + r = table_set_sort(table, (size_t) 0); + if (r < 0) + return table_log_sort_error(r); - table_set_header(table, arg_legend); + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); + if (r < 0) + return r; - if (OUTPUT_MODE_IS_JSON(arg_output)) - r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO); + if (arg_legend) { + if (table_isempty(table)) + printf("No %s.\n", type); else - r = table_print(table, NULL); - if (r < 0) - return table_log_print_error(r); + printf("\n%zu %s listed.\n", table_get_rows(table) - 1, type); } - if (arg_legend) { - if (table_get_rows(table) > 1) - printf("\n%zu %s listed.\n", table_get_rows(table) - 1, word); + return 0; +} + +static int list_sessions_table_add(Table *table, sd_bus_message *reply) { + int r; + + assert(table); + assert(reply); + + r = sd_bus_message_enter_container(reply, 'a', "(sussussbto)"); + if (r < 0) + return bus_log_parse_error(r); + + for (;;) { + const char *session_id, *user, *seat, *class, *tty; + uint32_t uid, leader_pid; + int idle; + uint64_t idle_timestamp_monotonic; + + r = sd_bus_message_read(reply, "(sussussbto)", + &session_id, + &uid, + &user, + &seat, + &leader_pid, + &class, + &tty, + &idle, + &idle_timestamp_monotonic, + /* object = */ NULL); + if (r < 0) + return bus_log_parse_error(r); + if (r == 0) + break; + + r = table_add_many(table, + TABLE_STRING, session_id, + TABLE_UID, (uid_t) uid, + TABLE_STRING, user, + TABLE_STRING, empty_to_null(seat), + TABLE_PID, (pid_t) leader_pid, + TABLE_STRING, class, + TABLE_STRING, empty_to_null(tty), + TABLE_BOOLEAN, idle); + if (r < 0) + return table_log_add_error(r); + + if (idle) + r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE_MONOTONIC, &idle_timestamp_monotonic); else - printf("No %s.\n", word); + r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); + if (r < 0) + return table_log_add_error(r); } + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + return 0; } -static int list_sessions(int argc, char *argv[], void *userdata) { +static int list_sessions_table_add_fallback(Table *table, sd_bus_message *reply, sd_bus *bus) { static const struct bus_properties_map map[] = { + { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) }, + { "Class", "s", NULL, offsetof(SessionStatusInfo, class) }, + { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) }, { "IdleHint", "b", NULL, offsetof(SessionStatusInfo, idle_hint) }, { "IdleSinceHintMonotonic", "t", NULL, offsetof(SessionStatusInfo, idle_hint_timestamp.monotonic) }, - { "State", "s", NULL, offsetof(SessionStatusInfo, state) }, - { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) }, {}, }; - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_(table_unrefp) Table *table = NULL; - sd_bus *bus = ASSERT_PTR(userdata); int r; - assert(argv); - - pager_open(arg_pager_flags); - - r = bus_call_method(bus, bus_login_mgr, "ListSessions", &error, &reply, NULL); - if (r < 0) - return log_error_errno(r, "Failed to list sessions: %s", bus_error_message(&error, r)); + assert(table); + assert(reply); + assert(bus); r = sd_bus_message_enter_container(reply, 'a', "(susso)"); if (r < 0) return bus_log_parse_error(r); - table = table_new("session", "uid", "user", "seat", "tty", "state", "idle", "since"); - if (!table) - return log_oom(); - - /* Right-align the first two fields (since they are numeric) */ - (void) table_set_align_percent(table, TABLE_HEADER_CELL(0), 100); - (void) table_set_align_percent(table, TABLE_HEADER_CELL(1), 100); - - (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (;;) { _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; const char *id, *user, *seat, *object; uint32_t uid; - _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; SessionStatusInfo i = {}; r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object); @@ -209,8 +245,9 @@ static int list_sessions(int argc, char *argv[], void *userdata) { TABLE_UID, (uid_t) uid, TABLE_STRING, user, TABLE_STRING, empty_to_null(seat), + TABLE_PID, i.leader, + TABLE_STRING, i.class, TABLE_STRING, empty_to_null(i.tty), - TABLE_STRING, i.state, TABLE_BOOLEAN, i.idle_hint); if (r < 0) return table_log_add_error(r); @@ -227,7 +264,49 @@ static int list_sessions(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return show_table(table, "sessions"); + return 0; +} + +static int list_sessions(int argc, char *argv[], void *userdata) { + sd_bus *bus = ASSERT_PTR(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_(table_unrefp) Table *table = NULL; + bool use_ex = true; + int r; + + assert(argv); + + r = bus_call_method(bus, bus_login_mgr, "ListSessionsEx", &error, &reply, NULL); + if (r < 0) { + if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) { + sd_bus_error_free(&error); + + use_ex = false; + r = bus_call_method(bus, bus_login_mgr, "ListSessions", &error, &reply, NULL); + } + if (r < 0) + return log_error_errno(r, "Failed to list sessions: %s", bus_error_message(&error, r)); + } + + table = table_new("session", "uid", "user", "seat", "leader", "class", "tty", "idle", "since"); + if (!table) + return log_oom(); + + /* Right-align the first two fields (since they are numeric) */ + (void) table_set_align_percent(table, TABLE_HEADER_CELL(0), 100); + (void) table_set_align_percent(table, TABLE_HEADER_CELL(1), 100); + + (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH); + + if (use_ex) + r = list_sessions_table_add(table, reply); + else + r = list_sessions_table_add_fallback(table, reply, bus); + if (r < 0) + return r; + + return list_table_print(table, "sessions"); } static int list_users(int argc, char *argv[], void *userdata) { @@ -246,8 +325,6 @@ static int list_users(int argc, char *argv[], void *userdata) { assert(argv); - pager_open(arg_pager_flags); - r = bus_call_method(bus, bus_login_mgr, "ListUsers", &error, &reply, NULL); if (r < 0) return log_error_errno(r, "Failed to list users: %s", bus_error_message(&error, r)); @@ -305,7 +382,7 @@ static int list_users(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return show_table(table, "users"); + return list_table_print(table, "users"); } static int list_seats(int argc, char *argv[], void *userdata) { @@ -317,8 +394,6 @@ static int list_seats(int argc, char *argv[], void *userdata) { assert(argv); - pager_open(arg_pager_flags); - r = bus_call_method(bus, bus_login_mgr, "ListSeats", &error, &reply, NULL); if (r < 0) return log_error_errno(r, "Failed to list seats: %s", bus_error_message(&error, r)); @@ -351,7 +426,7 @@ static int list_seats(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return show_table(table, "seats"); + return list_table_print(table, "seats"); } static int show_unit_cgroup( @@ -658,16 +733,15 @@ static int print_session_status_info(sd_bus *bus, const char *path) { show_journal_by_unit( stdout, i.scope, - NULL, + /* namespace = */ NULL, arg_output, - 0, + /* n_columns = */ 0, i.timestamp.monotonic, arg_lines, - 0, get_output_flags() | OUTPUT_BEGIN_NEWLINE, SD_JOURNAL_LOCAL_ONLY, - true, - NULL); + /* system_unit = */ true, + /* ellipsized = */ NULL); } return 0; @@ -764,16 +838,15 @@ static int print_user_status_info(sd_bus *bus, const char *path) { show_journal_by_unit( stdout, i.slice, - NULL, + /* namespace = */ NULL, arg_output, - 0, + /* n_columns = */ 0, i.timestamp.monotonic, arg_lines, - 0, get_output_flags() | OUTPUT_BEGIN_NEWLINE, SD_JOURNAL_LOCAL_ONLY, - true, - NULL); + /* system_unit = */ true, + /* ellipsized = */ NULL); } return 0; @@ -953,7 +1026,6 @@ static int get_bus_path_by_id( _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_ char *p = NULL; const char *path; int r; @@ -972,12 +1044,7 @@ static int get_bus_path_by_id( if (r < 0) return bus_log_parse_error(r); - p = strdup(path); - if (!p) - return log_oom(); - - *ret = TAKE_PTR(p); - return 0; + return strdup_to(ret, path); } static int show_session(int argc, char *argv[], void *userdata) { @@ -1442,7 +1509,10 @@ static int help(int argc, char *argv[], void *userdata) { " --kill-whom=WHOM Whom to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" " -n --lines=INTEGER Number of journal entries to show\n" - " -o --output=STRING Change journal output mode (short, short-precise,\n" + " --json=MODE Generate JSON output for list-sessions/users/seats\n" + " (takes one of pretty, short, or off)\n" + " -j Same as --json=pretty on tty, --json=short otherwise\n" + " -o --output=MODE Change journal output mode (short, short-precise,\n" " short-iso, short-iso-precise, short-full,\n" " short-monotonic, short-unix, short-delta,\n" " json, json-pretty, json-sse, json-seq, cat,\n" @@ -1464,6 +1534,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VALUE, ARG_NO_PAGER, ARG_NO_LEGEND, + ARG_JSON, ARG_KILL_WHOM, ARG_NO_ASK_PASSWORD, }; @@ -1477,6 +1548,7 @@ static int parse_argv(int argc, char *argv[]) { { "full", no_argument, NULL, 'l' }, { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "json", required_argument, NULL, ARG_JSON }, { "kill-whom", required_argument, NULL, ARG_KILL_WHOM }, { "signal", required_argument, NULL, 's' }, { "host", required_argument, NULL, 'H' }, @@ -1492,7 +1564,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hp:P:als:H:M:n:o:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hp:P:als:H:M:n:o:j", options, NULL)) >= 0) switch (c) { @@ -1546,7 +1618,19 @@ static int parse_argv(int argc, char *argv[]) { if (arg_output < 0) return log_error_errno(arg_output, "Unknown output '%s'.", optarg); - if (OUTPUT_MODE_IS_JSON(arg_output)) + break; + + case 'j': + arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO; + arg_legend = false; + break; + + case ARG_JSON: + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; + + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) arg_legend = false; break; |