From 25f15138382e4dcf55b2499bb89d915023c0e041 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 25 Jun 2024 09:30:09 -0400 Subject: [PATCH] Try both `--output=json` and `--json=short` when running `loginctl list-sessions` output (#1759) --- ee/consoleuser/consoleuser_linux.go | 49 ++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/ee/consoleuser/consoleuser_linux.go b/ee/consoleuser/consoleuser_linux.go index 0b1986a0d..17adb2249 100644 --- a/ee/consoleuser/consoleuser_linux.go +++ b/ee/consoleuser/consoleuser_linux.go @@ -20,19 +20,9 @@ type listSessionsResult []struct { } func CurrentUids(ctx context.Context) ([]string, error) { - cmd, err := allowedcmd.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--output=json") + sessions, err := listSessions(ctx) if err != nil { - return nil, fmt.Errorf("creating loginctl command: %w", err) - } - output, err := cmd.Output() - if err != nil { - return nil, fmt.Errorf("loginctl list-sessions: %w", err) - } - - // unmarshall json output into listSessionsResult - var sessions listSessionsResult - if err := json.Unmarshal(output, &sessions); err != nil { - return nil, fmt.Errorf("loginctl list-sessions unmarshall json output: %w", err) + return nil, fmt.Errorf("listing sessions: %w", err) } var uids []string @@ -73,3 +63,38 @@ func CurrentUids(ctx context.Context) ([]string, error) { return uids, nil } + +// listSessions execs `loginctl list-sessions` in order to retrieve the current list of sessions. +// Depending on the systemd version, we have to use different flags to output the results as JSON. +// We may want to attempt parsing the output regardless in the future -- see launcher #1522. +func listSessions(ctx context.Context) (listSessionsResult, error) { + var sessions listSessionsResult + + // Try with `--output=json` first, to support the more widely-used older versions of systemd + legacyCmd, err := allowedcmd.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--output=json") + if err != nil { + return nil, fmt.Errorf("creating loginctl command --no-legend --no-pager --output=json: %w", err) + } + legacyOut, err := legacyCmd.Output() + if err == nil { + // Newer versions of systemd ignore `--output=json` rather than returning an error, so we also + // need to unmarshal the result to confirm we got expected output. + if err := json.Unmarshal(legacyOut, &sessions); err == nil { + return sessions, nil + } + } + + cmd, err := allowedcmd.Loginctl(ctx, "list-sessions", "--no-legend", "--no-pager", "--json=short") + if err != nil { + return nil, fmt.Errorf("loginctl list-sessions --no-legend --no-pager --json=short: %w", err) + } + output, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("loginctl list-sessions: %w", err) + } + if err := json.Unmarshal(output, &sessions); err != nil { + return nil, fmt.Errorf("unmarshalling loginctl list-sessions output: %w", err) + } + + return sessions, nil +}