From 98a155962d384ad2dd1cd11449a0143b5cfae8ef Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 19 May 2023 14:21:44 +0200 Subject: [PATCH 1/4] test: extend test for loginctl list-* --- test/units/testsuite-35.sh | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh index e9d88e1c837..cae25499ad2 100755 --- a/test/units/testsuite-35.sh +++ b/test/units/testsuite-35.sh @@ -522,7 +522,9 @@ testcase_session_properties() { /usr/lib/systemd/tests/unit-tests/manual/test-session-properties "/org/freedesktop/login1/session/_3${s?}" /dev/tty2 } -testcase_list_users_sessions() { +testcase_list_users_sessions_seats() { + local session seat + if [[ ! -c /dev/tty2 ]]; then echo "/dev/tty2 does not exist, skipping test ${FUNCNAME[0]}." return @@ -534,10 +536,19 @@ testcase_list_users_sessions() { # Activate the session loginctl activate "$(loginctl --no-legend | awk '$3 == "logind-test-user" { print $1 }')" + session=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $1 }') + : check that we got a valid session id + busctl get-property org.freedesktop.login1 "/org/freedesktop/login1/session/_3${session?}" org.freedesktop.login1.Session Id + assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $2 }')" "$(id -ru logind-test-user)" + seat=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $4 }') + assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $5 }')" tty2 + assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $6 }')" active + + loginctl list-seats --no-legend | grep -Fwq "${seat?}" + assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $1 }')" "$(id -ru logind-test-user)" assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $3 }')" no assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $4 }')" active - assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $6 }')" active loginctl enable-linger logind-test-user assert_eq "$(loginctl list-users --no-legend | awk '$2 == "logind-test-user" { print $3 }')" yes From 86f128558d57586bd28c55eb63968eab3dc4b36e Mon Sep 17 00:00:00 2001 From: David Tardon Date: Tue, 23 May 2023 10:48:15 +0200 Subject: [PATCH 2/4] loginctl: shorten variable name --- src/login/loginctl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/login/loginctl.c b/src/login/loginctl.c index dfc738c6d02..505e3617458 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -142,7 +142,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) { (void) table_set_align_percent(table, TABLE_HEADER_CELL(1), 100); for (;;) { - _cleanup_(sd_bus_error_free) sd_bus_error error_property = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; _cleanup_free_ char *tty = NULL, *state = NULL; const char *id, *user, *seat, *object; uint32_t uid; @@ -158,17 +158,17 @@ static int list_sessions(int argc, char *argv[], void *userdata) { object, "org.freedesktop.login1.Session", "TTY", - &error_property, + &e, &tty); if (r < 0) { - if (sd_bus_error_has_name(&error_property, SD_BUS_ERROR_UNKNOWN_OBJECT)) + if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT)) /* The session is already closed when we're querying the property */ continue; log_warning_errno(r, "Failed to get TTY for session %s, ignoring: %s", - id, bus_error_message(&error_property, r)); + id, bus_error_message(&e, r)); - sd_bus_error_free(&error_property); + sd_bus_error_free(&e); } r = sd_bus_get_property_string(bus, @@ -176,15 +176,15 @@ static int list_sessions(int argc, char *argv[], void *userdata) { object, "org.freedesktop.login1.Session", "State", - &error_property, + &e, &state); if (r < 0) { - if (sd_bus_error_has_name(&error_property, SD_BUS_ERROR_UNKNOWN_OBJECT)) + if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT)) /* The session is already closed when we're querying the property */ continue; return log_error_errno(r, "Failed to get state for session %s: %s", - id, bus_error_message(&error_property, r)); + id, bus_error_message(&e, r)); } r = table_add_many(table, From 5b7d1536d0c2ccf0b7688490f31c92c1e766ea44 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 19 May 2023 13:33:58 +0200 Subject: [PATCH 3/4] loginctl: use bus_map_all_properties --- src/login/loginctl.c | 84 ++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 505e3617458..cf560aafdde 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -54,6 +54,27 @@ static OutputMode arg_output = OUTPUT_SHORT; STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep); +typedef struct SessionStatusInfo { + const char *id; + uid_t uid; + const char *name; + struct dual_timestamp timestamp; + unsigned vtnr; + const char *seat; + const char *tty; + const char *display; + bool remote; + const char *remote_host; + const char *remote_user; + const char *service; + pid_t leader; + const char *type; + const char *class; + const char *state; + const char *scope; + const char *desktop; +} SessionStatusInfo; + static OutputFlags get_output_flags(void) { return @@ -115,6 +136,13 @@ static int show_table(Table *table, const char *word) { } static int list_sessions(int argc, char *argv[], void *userdata) { + + static const struct bus_properties_map map[] = { + { "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; @@ -143,9 +171,10 @@ static int list_sessions(int argc, char *argv[], void *userdata) { for (;;) { _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; - _cleanup_free_ char *tty = NULL, *state = 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); if (r < 0) @@ -153,38 +182,14 @@ static int list_sessions(int argc, char *argv[], void *userdata) { if (r == 0) break; - r = sd_bus_get_property_string(bus, - "org.freedesktop.login1", - object, - "org.freedesktop.login1.Session", - "TTY", - &e, - &tty); + r = bus_map_all_properties(bus, "org.freedesktop.login1", object, map, BUS_MAP_BOOLEAN_AS_BOOL, &e, &m, &i); if (r < 0) { if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT)) /* The session is already closed when we're querying the property */ continue; - log_warning_errno(r, "Failed to get TTY for session %s, ignoring: %s", + log_warning_errno(r, "Failed to get properties of session %s, ignoring: %s", id, bus_error_message(&e, r)); - - sd_bus_error_free(&e); - } - - r = sd_bus_get_property_string(bus, - "org.freedesktop.login1", - object, - "org.freedesktop.login1.Session", - "State", - &e, - &state); - if (r < 0) { - if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT)) - /* The session is already closed when we're querying the property */ - continue; - - return log_error_errno(r, "Failed to get state for session %s: %s", - id, bus_error_message(&e, r)); } r = table_add_many(table, @@ -192,8 +197,8 @@ static int list_sessions(int argc, char *argv[], void *userdata) { TABLE_UID, (uid_t) uid, TABLE_STRING, user, TABLE_STRING, seat, - TABLE_STRING, strna(tty), - TABLE_STRING, state); + TABLE_STRING, strna(i.tty), + TABLE_STRING, i.state); if (r < 0) return table_log_add_error(r); } @@ -376,27 +381,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit return 0; } -typedef struct SessionStatusInfo { - const char *id; - uid_t uid; - const char *name; - struct dual_timestamp timestamp; - unsigned vtnr; - const char *seat; - const char *tty; - const char *display; - bool remote; - const char *remote_host; - const char *remote_user; - const char *service; - pid_t leader; - const char *type; - const char *class; - const char *state; - const char *scope; - const char *desktop; -} SessionStatusInfo; - typedef struct UserStatusInfo { uid_t uid; bool linger; From 556723e738b96a5c2b2d45a96b87b7b80e0c5664 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Fri, 19 May 2023 14:03:09 +0200 Subject: [PATCH 4/4] loginctl: show session idle status in list-sessions --- src/login/loginctl.c | 31 +++++++++++++++++++++---------- test/units/testsuite-35.sh | 2 ++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/login/loginctl.c b/src/login/loginctl.c index cf560aafdde..28f4231ac1f 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -73,6 +73,8 @@ typedef struct SessionStatusInfo { const char *state; const char *scope; const char *desktop; + bool idle_hint; + dual_timestamp idle_hint_timestamp; } SessionStatusInfo; static OutputFlags get_output_flags(void) { @@ -138,8 +140,10 @@ static int show_table(Table *table, const char *word) { static int list_sessions(int argc, char *argv[], void *userdata) { static const struct bus_properties_map map[] = { - { "State", "s", NULL, offsetof(SessionStatusInfo, state) }, - { "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) }, {}, }; @@ -161,7 +165,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - table = table_new("session", "uid", "user", "seat", "tty", "state"); + table = table_new("session", "uid", "user", "seat", "tty", "state", "idle", "since"); if (!table) return log_oom(); @@ -184,12 +188,11 @@ static int list_sessions(int argc, char *argv[], void *userdata) { r = bus_map_all_properties(bus, "org.freedesktop.login1", object, map, BUS_MAP_BOOLEAN_AS_BOOL, &e, &m, &i); if (r < 0) { - if (sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT)) - /* The session is already closed when we're querying the property */ - continue; - - log_warning_errno(r, "Failed to get properties of session %s, ignoring: %s", - id, bus_error_message(&e, r)); + log_full_errno(sd_bus_error_has_name(&e, SD_BUS_ERROR_UNKNOWN_OBJECT) ? LOG_DEBUG : LOG_WARNING, + r, + "Failed to get properties of session %s, ignoring: %s", + id, bus_error_message(&e, r)); + continue; } r = table_add_many(table, @@ -198,7 +201,15 @@ static int list_sessions(int argc, char *argv[], void *userdata) { TABLE_STRING, user, TABLE_STRING, seat, TABLE_STRING, strna(i.tty), - TABLE_STRING, i.state); + TABLE_STRING, i.state, + TABLE_BOOLEAN, i.idle_hint); + if (r < 0) + return table_log_add_error(r); + + if (i.idle_hint) + r = table_add_cell(table, NULL, TABLE_TIMESTAMP_RELATIVE, &i.idle_hint_timestamp.monotonic); + else + r = table_add_cell(table, NULL, TABLE_EMPTY, NULL); if (r < 0) return table_log_add_error(r); } diff --git a/test/units/testsuite-35.sh b/test/units/testsuite-35.sh index cae25499ad2..659882ed7ae 100755 --- a/test/units/testsuite-35.sh +++ b/test/units/testsuite-35.sh @@ -543,6 +543,8 @@ testcase_list_users_sessions_seats() { seat=$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $4 }') assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $5 }')" tty2 assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $6 }')" active + assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $7 }')" no + assert_eq "$(loginctl list-sessions --no-legend | awk '$3 == "logind-test-user" { print $8 }')" '' loginctl list-seats --no-legend | grep -Fwq "${seat?}"