]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/login/loginctl.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / login / loginctl.c
index 8cea2829884e54a03f58709b79c493d1c6d6c960..ab1b56201a37be0f0be339721ddb95c26ce8932e 100644 (file)
@@ -1,9 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
-/***
-  This file is part of systemd.
-
-  Copyright 2010 Lennart Poettering
-***/
 
 #include <errno.h>
 #include <getopt.h>
 #include "log.h"
 #include "logs-show.h"
 #include "macro.h"
+#include "main-func.h"
 #include "pager.h"
 #include "parse-util.h"
+#include "pretty-print.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "sigbus.h"
 #include "signal-util.h"
 #include "spawn-polkit-agent.h"
@@ -42,7 +40,7 @@ static char **arg_property = NULL;
 static bool arg_all = false;
 static bool arg_value = false;
 static bool arg_full = false;
-static bool arg_no_pager = false;
+static PagerFlags arg_pager_flags = 0;
 static bool arg_legend = true;
 static const char *arg_kill_who = NULL;
 static int arg_signal = SIGTERM;
@@ -52,6 +50,8 @@ static bool arg_ask_password = true;
 static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
 
+STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
+
 static OutputFlags get_output_flags(void) {
 
         return
@@ -101,7 +101,10 @@ static int show_table(Table *table, const char *word) {
 
                 table_set_header(table, arg_legend);
 
-                r = table_print(table, NULL);
+                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);
+                else
+                        r = table_print(table, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to show table: %m");
         }
@@ -126,7 +129,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
         assert(bus);
         assert(argv);
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         r = sd_bus_call_method(
                         bus,
@@ -143,7 +146,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");
+        table = table_new("session", "uid", "user", "seat", "tty");
         if (!table)
                 return log_oom();
 
@@ -207,7 +210,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
         assert(bus);
         assert(argv);
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         r = sd_bus_call_method(
                         bus,
@@ -224,17 +227,17 @@ static int list_users(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("UID", "USER");
+        table = table_new("uid", "user");
         if (!table)
                 return log_oom();
 
         (void) table_set_align_percent(table, TABLE_HEADER_CELL(0), 100);
 
         for (;;) {
-                const char *user, *object;
+                const char *user;
                 uint32_t uid;
 
-                r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object);
+                r = sd_bus_message_read(reply, "(uso)", &uid, &user, NULL);
                 if (r < 0)
                         return bus_log_parse_error(r);
                 if (r == 0)
@@ -264,7 +267,7 @@ static int list_seats(int argc, char *argv[], void *userdata) {
         assert(bus);
         assert(argv);
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         r = sd_bus_call_method(
                         bus,
@@ -281,14 +284,14 @@ static int list_seats(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("SEAT");
+        table = table_new("seat");
         if (!table)
                 return log_oom();
 
         for (;;) {
-                const char *seat, *object;
+                const char *seat;
 
-                r = sd_bus_message_read(reply, "(so)", &seat, &object);
+                r = sd_bus_message_read(reply, "(so)", &seat, NULL);
                 if (r < 0)
                         return bus_log_parse_error(r);
                 if (r == 0)
@@ -351,7 +354,7 @@ typedef struct SessionStatusInfo {
         uid_t uid;
         const char *name;
         struct dual_timestamp timestamp;
-        unsigned int vtnr;
+        unsigned vtnr;
         const char *seat;
         const char *tty;
         const char *display;
@@ -474,8 +477,9 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
 
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
-        char since2[FORMAT_TIMESTAMP_MAX], *s2;
+        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
+        char since2[FORMAT_TIMESTAMP_MAX];
+        const char *s1, *s2;
         SessionStatusInfo i = {};
         int r;
 
@@ -605,8 +609,9 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
 
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
-        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
-        char since2[FORMAT_TIMESTAMP_MAX], *s2;
+        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
+        char since2[FORMAT_TIMESTAMP_MAX];
+        const char *s1, *s2;
         _cleanup_(user_status_info_clear) UserStatusInfo i = {};
         int r;
 
@@ -726,15 +731,7 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
         return 0;
 }
 
-#define property(name, fmt, ...)                                        \
-        do {                                                            \
-                if (value)                                              \
-                        printf(fmt "\n", __VA_ARGS__);                  \
-                else                                                    \
-                        printf("%s=" fmt "\n", name, __VA_ARGS__);      \
-        } while (0)
-
-static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
+static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
         char type;
         const char *contents;
         int r;
@@ -758,7 +755,7 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
                                 return bus_log_parse_error(r);
 
                         if (all || !isempty(s))
-                                property(name, "%s", s);
+                                bus_print_property_value(name, expected_value, value, "%s", s);
 
                         return 1;
 
@@ -769,12 +766,12 @@ static int print_property(const char *name, sd_bus_message *m, bool value, bool
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        if (!uid_is_valid(uid)) {
-                                log_error("Invalid user ID: " UID_FMT, uid);
-                                return -EINVAL;
-                        }
+                        if (!uid_is_valid(uid))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid user ID: " UID_FMT,
+                                                       uid);
 
-                        property(name, UID_FMT, uid);
+                        bus_print_property_value(name, expected_value, value, UID_FMT, uid);
                         return 1;
                 }
                 break;
@@ -846,7 +843,7 @@ static int show_session(int argc, char *argv[], void *userdata) {
 
         properties = !strstr(argv[0], "status");
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         if (argc <= 1) {
                 const char *session, *p = "/org/freedesktop/login1/session/self";
@@ -859,10 +856,9 @@ static int show_session(int argc, char *argv[], void *userdata) {
                 session = getenv("XDG_SESSION_ID");
                 if (session) {
                         r = get_session_path(bus, session, &error, &path);
-                        if (r < 0) {
-                                log_error("Failed to get session path: %s", bus_error_message(&error, r));
-                                return r;
-                        }
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get session path: %s", bus_error_message(&error, r));
+
                         p = path;
                 }
 
@@ -871,10 +867,8 @@ static int show_session(int argc, char *argv[], void *userdata) {
 
         for (i = 1; i < argc; i++) {
                 r = get_session_path(bus, argv[i], &error, &path);
-                if (r < 0) {
-                        log_error("Failed to get session path: %s", bus_error_message(&error, r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get session path: %s", bus_error_message(&error, r));
 
                 if (properties)
                         r = show_properties(bus, path, &new_line);
@@ -898,7 +892,7 @@ static int show_user(int argc, char *argv[], void *userdata) {
 
         properties = !strstr(argv[0], "status");
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         if (argc <= 1) {
                 /* If not argument is specified inspect the manager
@@ -915,7 +909,7 @@ static int show_user(int argc, char *argv[], void *userdata) {
                 const char *path = NULL;
                 uid_t uid;
 
-                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
+                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
                 if (r < 0)
                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
 
@@ -927,10 +921,8 @@ static int show_user(int argc, char *argv[], void *userdata) {
                                 "GetUser",
                                 &error, &reply,
                                 "u", (uint32_t) uid);
-                if (r < 0) {
-                        log_error("Failed to get user: %s", bus_error_message(&error, r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get user: %s", bus_error_message(&error, r));
 
                 r = sd_bus_message_read(reply, "o", &path);
                 if (r < 0)
@@ -958,7 +950,7 @@ static int show_seat(int argc, char *argv[], void *userdata) {
 
         properties = !strstr(argv[0], "status");
 
-        (void) pager_open(arg_no_pager, false);
+        (void) pager_open(arg_pager_flags);
 
         if (argc <= 1) {
                 /* If not argument is specified inspect the manager
@@ -982,10 +974,8 @@ static int show_seat(int argc, char *argv[], void *userdata) {
                                 "GetSeat",
                                 &error, &reply,
                                 "s", argv[i]);
-                if (r < 0) {
-                        log_error("Failed to get seat: %s", bus_error_message(&error, r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get seat: %s", bus_error_message(&error, r));
 
                 r = sd_bus_message_read(reply, "o", &path);
                 if (r < 0)
@@ -1039,10 +1029,8 @@ static int activate(int argc, char *argv[], void *userdata) {
                                                                       "ActivateSession",
                                 &error, NULL,
                                 "s", argv[i]);
-                if (r < 0) {
-                        log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1071,10 +1059,8 @@ static int kill_session(int argc, char *argv[], void *userdata) {
                         "KillSession",
                         &error, NULL,
                         "ssi", argv[i], arg_kill_who, arg_signal);
-                if (r < 0) {
-                        log_error("Could not kill session: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not kill session: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1111,7 +1097,7 @@ static int enable_linger(int argc, char *argv[], void *userdata) {
                 if (isempty(argv[i]))
                         uid = UID_INVALID;
                 else {
-                        r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
+                        r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
                 }
@@ -1124,10 +1110,8 @@ static int enable_linger(int argc, char *argv[], void *userdata) {
                         "SetUserLinger",
                         &error, NULL,
                         "ubb", (uint32_t) uid, b, true);
-                if (r < 0) {
-                        log_error("Could not enable linger: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not enable linger: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1146,7 +1130,7 @@ static int terminate_user(int argc, char *argv[], void *userdata) {
         for (i = 1; i < argc; i++) {
                 uid_t uid;
 
-                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
+                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
                 if (r < 0)
                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
 
@@ -1158,10 +1142,8 @@ static int terminate_user(int argc, char *argv[], void *userdata) {
                         "TerminateUser",
                         &error, NULL,
                         "u", (uint32_t) uid);
-                if (r < 0) {
-                        log_error("Could not terminate user: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not terminate user: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1183,7 +1165,7 @@ static int kill_user(int argc, char *argv[], void *userdata) {
         for (i = 1; i < argc; i++) {
                 uid_t uid;
 
-                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
+                r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
                 if (r < 0)
                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
 
@@ -1195,10 +1177,8 @@ static int kill_user(int argc, char *argv[], void *userdata) {
                         "KillUser",
                         &error, NULL,
                         "ui", (uint32_t) uid, arg_signal);
-                if (r < 0) {
-                        log_error("Could not kill user: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not kill user: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1225,10 +1205,8 @@ static int attach(int argc, char *argv[], void *userdata) {
                         &error, NULL,
                         "ssb", argv[1], argv[i], true);
 
-                if (r < 0) {
-                        log_error("Could not attach device: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not attach device: %s", bus_error_message(&error, -r));
         }
 
         return 0;
@@ -1253,9 +1231,9 @@ static int flush_devices(int argc, char *argv[], void *userdata) {
                         &error, NULL,
                         "b", true);
         if (r < 0)
-                log_error("Could not flush devices: %s", bus_error_message(&error, -r));
+                return log_error_errno(r, "Could not flush devices: %s", bus_error_message(&error, -r));
 
-        return r;
+        return 0;
 }
 
 static int lock_sessions(int argc, char *argv[], void *userdata) {
@@ -1277,9 +1255,9 @@ static int lock_sessions(int argc, char *argv[], void *userdata) {
                         &error, NULL,
                         NULL);
         if (r < 0)
-                log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
+                return log_error_errno(r, "Could not lock sessions: %s", bus_error_message(&error, -r));
 
-        return r;
+        return 0;
 }
 
 static int terminate_seat(int argc, char *argv[], void *userdata) {
@@ -1302,16 +1280,22 @@ static int terminate_seat(int argc, char *argv[], void *userdata) {
                         "TerminateSeat",
                         &error, NULL,
                         "s", argv[i]);
-                if (r < 0) {
-                        log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Could not terminate seat: %s", bus_error_message(&error, -r));
         }
 
         return 0;
 }
 
 static int help(int argc, char *argv[], void *userdata) {
+        _cleanup_free_ char *link = NULL;
+        int r;
+
+        (void) pager_open(arg_pager_flags);
+
+        r = terminal_urlify_man("loginctl", "1", &link);
+        if (r < 0)
+                return log_oom();
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the login manager.\n\n"
@@ -1332,7 +1316,8 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -o --output=STRING       Change journal output mode (short, short-precise,\n"
                "                             short-iso, short-iso-precise, short-full,\n"
                "                             short-monotonic, short-unix, verbose, export,\n"
-               "                             json, json-pretty, json-sse, cat)\n"
+               "                             json, json-pretty, json-sse, json-seq, cat,\n"
+               "                             with-unit)\n"
                "Session Commands:\n"
                "  list-sessions            List sessions\n"
                "  session-status [ID...]   Show session status\n"
@@ -1359,7 +1344,10 @@ static int help(int argc, char *argv[], void *userdata) {
                "  attach NAME DEVICE...    Attach one or more devices to a seat\n"
                "  flush-devices            Flush all device associations\n"
                "  terminate-seat NAME...   Terminate all sessions on one or more seats\n"
-               , program_invocation_short_name);
+               "\nSee the %s for details.\n"
+               , program_invocation_short_name
+               , link
+        );
 
         return 0;
 }
@@ -1404,8 +1392,7 @@ static int parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        help(0, NULL, NULL);
-                        return 0;
+                        return help(0, NULL, NULL);
 
                 case ARG_VERSION:
                         return version();
@@ -1435,10 +1422,9 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case 'n':
-                        if (safe_atou(optarg, &arg_lines) < 0) {
-                                log_error("Failed to parse lines '%s'", optarg);
-                                return -EINVAL;
-                        }
+                        if (safe_atou(optarg, &arg_lines) < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Failed to parse lines '%s'", optarg);
                         break;
 
                 case 'o':
@@ -1448,14 +1434,17 @@ static int parse_argv(int argc, char *argv[]) {
                         }
 
                         arg_output = output_mode_from_string(optarg);
-                        if (arg_output < 0) {
-                                log_error("Unknown output '%s'.", optarg);
-                                return -EINVAL;
-                        }
+                        if (arg_output < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Unknown output '%s'.", optarg);
+
+                        if (OUTPUT_MODE_IS_JSON(arg_output))
+                                arg_legend = false;
+
                         break;
 
                 case ARG_NO_PAGER:
-                        arg_no_pager = true;
+                        arg_pager_flags |= PAGER_DISABLE;
                         break;
 
                 case ARG_NO_LEGEND:
@@ -1477,10 +1466,9 @@ static int parse_argv(int argc, char *argv[]) {
                         }
 
                         arg_signal = signal_from_string(optarg);
-                        if (arg_signal < 0) {
-                                log_error("Failed to parse signal string %s.", optarg);
-                                return -EINVAL;
-                        }
+                        if (arg_signal < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Failed to parse signal string %s.", optarg);
                         break;
 
                 case 'H':
@@ -1536,37 +1524,30 @@ static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
         return dispatch_verb(argc, argv, verbs, bus);
 }
 
-int main(int argc, char *argv[]) {
-        sd_bus *bus = NULL;
+static int run(int argc, char *argv[]) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         int r;
 
         setlocale(LC_ALL, "");
         log_parse_environment();
         log_open();
+
+        /* The journal merging logic potentially needs a lot of fds. */
+        (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
+
         sigbus_install();
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                goto finish;
+                return r;
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
-        if (r < 0) {
-                log_error_errno(r, "Failed to create bus connection: %m");
-                goto finish;
-        }
-
-        sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
-
-        r = loginctl_main(argc, argv, bus);
-
-finish:
-        /* make sure we terminate the bus connection first, and then close the
-         * pager, see issue #3543 for the details. */
-        sd_bus_flush_close_unref(bus);
-        pager_close();
-        polkit_agent_close();
+        if (r < 0)
+                return log_error_errno(r, "Failed to create bus connection: %m");
 
-        strv_free(arg_property);
+        (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
 
-        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+        return loginctl_main(argc, argv, bus);
 }
+
+DEFINE_MAIN_FUNCTION(run);