/* 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"
+#include "string-table.h"
#include "strv.h"
#include "sysfs-show.h"
#include "terminal-util.h"
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;
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
assert(bus);
assert(argv);
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = sd_bus_call_method(
bus,
assert(bus);
assert(argv);
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = sd_bus_call_method(
bus,
(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)
assert(bus);
assert(argv);
- (void) pager_open(arg_no_pager, false);
+ (void) pager_open(arg_pager_flags);
r = sd_bus_call_method(
bus,
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)
uid_t uid;
const char *name;
struct dual_timestamp timestamp;
- unsigned int vtnr;
+ unsigned vtnr;
const char *seat;
const char *tty;
const char *display;
_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;
_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;
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;
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;
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;
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";
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;
}
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);
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
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]);
"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)
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
"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)
"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;
"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;
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]);
}
"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;
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]);
"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;
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]);
"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;
&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;
&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) {
&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) {
"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"
" -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"
" 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;
}
switch (c) {
case 'h':
- help(0, NULL, NULL);
- return 0;
+ return help(0, NULL, NULL);
case ARG_VERSION:
return version();
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':
- arg_output = output_mode_from_string(optarg);
- if (arg_output < 0) {
- log_error("Unknown output '%s'.", optarg);
- return -EINVAL;
+ if (streq(optarg, "help")) {
+ DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
+ return 0;
}
+
+ arg_output = output_mode_from_string(optarg);
+ if (arg_output < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Unknown output '%s'.", optarg);
break;
case ARG_NO_PAGER:
- arg_no_pager = true;
+ arg_pager_flags |= PAGER_DISABLE;
break;
case ARG_NO_LEGEND:
break;
case 's':
- arg_signal = signal_from_string(optarg);
- if (arg_signal < 0) {
- log_error("Failed to parse signal string %s.", optarg);
- return -EINVAL;
+ if (streq(optarg, "help")) {
+ DUMP_STRING_TABLE(signal, int, _NSIG);
+ return 0;
}
+
+ arg_signal = signal_from_string(optarg);
+ if (arg_signal < 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Failed to parse signal string %s.", optarg);
break;
case 'H':
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);