char *seat;
char *tty;
char *display;
- bool remote;
+ int remote;
char *remote_host;
char *remote_user;
char *service;
typedef struct UserStatusInfo {
uid_t uid;
- bool linger;
+ int linger;
char *name;
struct dual_timestamp timestamp;
char *state;
return 0;
}
-/* Ask elogind, which might grant access to unprivileged users
- * through PolicyKit */
+static int elogind_cancel_shutdown(sd_bus *bus) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CancelScheduledShutdown",
+ &error,
+ NULL, NULL);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to talk to elogind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
+static int elogind_schedule_shutdown(sd_bus *bus, enum action a) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *method = NULL;
+ int r;
+
+ if (!bus)
+ return -EIO;
+
+ polkit_agent_open_if_enabled();
+
+ switch (a) {
+
+ case ACTION_POWEROFF:
+ method = "poweroff";
+ break;
+
+ case ACTION_REBOOT:
+ method = "reboot";
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ r = logind_set_wall_message(bus, NULL);
+
+ if (r < 0) {
+ log_warning_errno(r, "Failed to set wall message, ignoring: %s",
+ bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ }
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ScheduleShutdown",
+ &error,
+ NULL,
+ "st",
+ method,
+ arg_when);
+
+ if (r < 0)
+ log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+
+ return r;
+}
+
static int elogind_reboot(sd_bus *bus, enum action a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method;
+ const char *method = NULL;
int r;
static const char *table[_ACTION_MAX] = {
[ACTION_REBOOT] = "The system is going down for reboot NOW!",
- [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
- [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
+ [ACTION_POWEROFF] = "The system is going down for power-off NOW!"
};
if (!bus)
method = "HybridSleep";
break;
- case ACTION_CANCEL_SHUTDOWN:
- method = "CancelScheduledShutdown";
- break;
-
default:
return -EINVAL;
}
r = logind_set_wall_message(bus, table[a]);
+
if (r < 0) {
log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
+ /* Now call elogind itself to request the operation */
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
method,
&error,
NULL,
- "b", arg_ask_password);
+ "b",
+ arg_ask_password);
+
if (r < 0)
log_error("Failed to execute operation: %s", bus_error_message(&error, r));
if (c <= 0)
return 0;
- log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
+ log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'loginctl -i %s'.",
action_table[a].verb);
return -EPERM;
sd_bus *bus = userdata;
enum action a;
int r;
+ char** wall = NULL;
assert(argv);
a = verb_to_action(argv[0]);
+ /* Switch to cancel shutdown, if a shutdown action was requested,
+ and the option to cancel it was set: */
+ if ( IN_SET(a, ACTION_POWEROFF, ACTION_REBOOT)
+ && (arg_action == ACTION_CANCEL_SHUTDOWN) )
+ return elogind_cancel_shutdown(bus);
+
r = check_inhibitors(bus, a);
if (r < 0)
return r;
- /* Now power off actions in chroot environments */
+ /* No power off actions in chroot environments */
if ((a == ACTION_POWEROFF ||
a == ACTION_REBOOT) &&
(running_in_chroot() > 0) ) {
return 0;
}
- /* Switch to cancel shutdown, if a shutdown action was requested,
- and the option to cancel it was set: */
- if ((a == ACTION_POWEROFF ||
- a == ACTION_REBOOT) &&
- (arg_action == ACTION_CANCEL_SHUTDOWN))
- return elogind_reboot(bus, arg_action);
+ /* Check time arguments */
+ if ( IN_SET(a, ACTION_POWEROFF, ACTION_REBOOT)
+ && (argc > 1)
+ && (arg_action != ACTION_CANCEL_SHUTDOWN) ) {
+ r = parse_shutdown_time_spec(argv[1], &arg_when);
+ if (r < 0) {
+ log_error("Failed to parse time specification: %s", argv[optind]);
+ return r;
+ }
+ } else
+ arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
- /* Otherwise perform requested action */
- if (a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_SUSPEND ||
- a == ACTION_HIBERNATE ||
- a == ACTION_HYBRID_SLEEP)
- return elogind_reboot(bus, a);
+ /* The optional user wall message must be set */
+ if ((argc > 1) && (arg_action == ACTION_CANCEL_SHUTDOWN) )
+ /* No time argument for shutdown cancel */
+ wall = argv + 1;
+ else if (argc > 2)
+ /* We skip the time argument */
+ wall = argv + 2;
+
+ if (wall) {
+ arg_wall = strv_copy(wall);
+ if (!arg_wall)
+ return log_oom();
+ }
+
+ /* Perform requested action */
+ if (IN_SET(a,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP)) {
+ if (arg_when > 0)
+ return elogind_schedule_shutdown(bus, a);
+ else
+ return elogind_reboot(bus, a);
+ }
return -EOPNOTSUPP;
}
" -o --output=STRING Change journal output mode (short, short-monotonic,\n"
" verbose, export, json, json-pretty, json-sse, cat)\n\n"
#endif // 0
- " -c Cancel a pending shutdown\n"
- " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n"
+ " -c Cancel a pending shutdown or reboot\n"
+ " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n"
"Session Commands:\n"
- " list-sessions List sessions\n"
- " session-status [ID...] Show session status\n"
- " show-session [ID...] Show properties of sessions or the manager\n"
- " activate [ID] Activate a session\n"
- " lock-session [ID...] Screen lock one or more sessions\n"
- " unlock-session [ID...] Screen unlock one or more sessions\n"
- " lock-sessions Screen lock all current sessions\n"
- " unlock-sessions Screen unlock all current sessions\n"
- " terminate-session ID... Terminate one or more sessions\n"
- " kill-session ID... Send signal to processes of a session\n\n"
+ " list-sessions List sessions\n"
+ " session-status [ID...] Show session status\n"
+ " show-session [ID...] Show properties of sessions or the manager\n"
+ " activate [ID] Activate a session\n"
+ " lock-session [ID...] Screen lock one or more sessions\n"
+ " unlock-session [ID...] Screen unlock one or more sessions\n"
+ " lock-sessions Screen lock all current sessions\n"
+ " unlock-sessions Screen unlock all current sessions\n"
+ " terminate-session ID... Terminate one or more sessions\n"
+ " kill-session ID... Send signal to processes of a session\n\n"
"User Commands:\n"
- " list-users List users\n"
- " user-status [USER...] Show user status\n"
- " show-user [USER...] Show properties of users or the manager\n"
- " enable-linger [USER...] Enable linger state of one or more users\n"
- " disable-linger [USER...] Disable linger state of one or more users\n"
- " terminate-user USER... Terminate all sessions of one or more users\n"
- " kill-user USER... Send signal to processes of a user\n\n"
+ " list-users List users\n"
+ " user-status [USER...] Show user status\n"
+ " show-user [USER...] Show properties of users or the manager\n"
+ " enable-linger [USER...] Enable linger state of one or more users\n"
+ " disable-linger [USER...] Disable linger state of one or more users\n"
+ " terminate-user USER... Terminate all sessions of one or more users\n"
+ " kill-user USER... Send signal to processes of a user\n\n"
"Seat Commands:\n"
- " list-seats List seats\n"
- " seat-status [NAME...] Show seat status\n"
- " show-seat [NAME...] Show properties of seats or the manager\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"
+ " list-seats List seats\n"
+ " seat-status [NAME...] Show seat status\n"
+ " show-seat [NAME...] Show properties of seats or the manager\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"
"System Commands:\n"
- " poweroff Turn off the machine\n"
- " reboot Reboot the machine\n"
- " suspend Suspend the machine to memory\n"
- " hibernate Suspend the machine to disk\n"
- " hybrid-sleep Suspend the machine to memory and disk\n"
+ " poweroff [TIME] [WALL...] Turn off the machine\n"
+ " reboot [TIME] [WALL...] Reboot the machine\n"
+ " suspend Suspend the machine to memory\n"
+ " hibernate Suspend the machine to disk\n"
+ " hybrid-sleep Suspend the machine to memory and disk\n"
, program_invocation_short_name);
return 0;
{}
};
- char **wall = NULL;
int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:ci", options, NULL)) >= 0) {
switch (c) {
default:
assert_not_reached("Unhandled option");
}
-
- if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
- r = parse_shutdown_time_spec(argv[optind], &arg_when);
- if (r < 0) {
- log_error("Failed to parse time specification: %s", argv[optind]);
- return r;
- }
- } else
- arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
-
- if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
- /* No time argument for shutdown cancel */
- wall = argv + optind;
- else if (argc > optind + 1)
- /* We skip the time argument */
- wall = argv + optind + 1;
-
- if (wall) {
- arg_wall = strv_copy(wall);
- if (!arg_wall)
- return log_oom();
}
- optind = argc;
-
return 1;
}
{ "attach", 3, VERB_ANY, 0, attach },
{ "flush-devices", VERB_ANY, 1, 0, flush_devices },
{ "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
- { "poweroff", VERB_ANY, 1, 0, start_special },
- { "reboot", VERB_ANY, 1, 0, start_special },
+ { "poweroff", VERB_ANY, VERB_ANY, 0, start_special },
+ { "reboot", VERB_ANY, VERB_ANY, 0, start_special },
{ "suspend", VERB_ANY, 1, 0, start_special },
{ "hibernate", VERB_ANY, 1, 0, start_special },
{ "hybrid-sleep", VERB_ANY, 1, 0, start_special },
{}
};
+ if ((argc == optind) && (ACTION_CANCEL_SHUTDOWN == arg_action))
+ return elogind_cancel_shutdown(bus);
+
return dispatch_verb(argc, argv, verbs, bus);
}
int main(int argc, char *argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
}
sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
-
r = loginctl_main(argc, argv, bus);
finish:
+ sd_bus_flush_close_unref(bus);
+
pager_close();
polkit_agent_close();