elogind_action arg_action = _ACTION_INVALID;
bool arg_ask_password = true;
+bool arg_dry_run = false;
+bool arg_quiet = false;
bool arg_ignore_inhibitors = false;
bool arg_no_wall = false;
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
HandleAction action;
const char* verb;
} action_table[_ACTION_MAX] = {
- [ACTION_POWEROFF] = { HANDLE_POWEROFF, "poweroff", },
- [ACTION_REBOOT] = { HANDLE_REBOOT, "reboot", },
- [ACTION_SUSPEND] = { HANDLE_SUSPEND, "suspend", },
- [ACTION_HIBERNATE] = { HANDLE_HIBERNATE, "hibernate", },
- [ACTION_HYBRID_SLEEP] = { HANDLE_HYBRID_SLEEP, "hybrid-sleep" },
+ [ACTION_HALT] = { HANDLE_HALT, "halt" },
+ [ACTION_POWEROFF] = { HANDLE_POWEROFF, "poweroff", },
+ [ACTION_REBOOT] = { HANDLE_REBOOT, "reboot", },
+ [ACTION_KEXEC] = { HANDLE_KEXEC, "kexec", },
+ [ACTION_SUSPEND] = { HANDLE_SUSPEND, "suspend", },
+ [ACTION_HIBERNATE] = { HANDLE_HIBERNATE, "hibernate", },
+ [ACTION_HYBRID_SLEEP] = { HANDLE_HYBRID_SLEEP, "hybrid-sleep" },
+ [ACTION_SUSPEND_THEN_HIBERNATE] = { HANDLE_SUSPEND_THEN_HIBERNATE, "suspend-then-hibernate" }
+ /* ACTION_CANCEL_SHUTDOWN is handled differently */
};
static int elogind_set_wall_message(sd_bus* bus, const char* msg);
return _ACTION_INVALID;
}
+/* Original:
+ * systemctl/systemctl.c:3314:logind_check_inhibitors()
+ */
static int check_inhibitors(sd_bus* bus, enum elogind_action a) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **sessions = NULL;
if (!on_tty())
return 0;
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ return 0;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
if (!sv)
return log_oom();
- if ((pid_t) pid < 0)
- return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
+ if (!pid_is_valid((pid_t) pid)) {
+ log_error("Invalid PID "PID_FMT".", (pid_t) pid);
+ return -ERANGE;
+ }
if (!strv_contains(sv,
IN_SET(a,
if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
continue;
- if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
+ if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "wayland", "tty", "mir"))
continue;
sd_session_get_tty(*s, &tty);
if (c <= 0)
return 0;
- log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'loginctl -i %s'.",
+ log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'loginctl %s -i'.",
action_table[a].verb);
return -EPERM;
}
+/* Original:
+ * systemctl/systemctl.c:8683:logind_cancel_shutdown()
+ */
int elogind_cancel_shutdown(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- r = elogind_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);
- }
+ (void) elogind_set_wall_message(bus, NULL);
r = sd_bus_call_method(
bus,
&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 log_warning_errno(r,
+ "Failed to talk to elogind, shutdown hasn't been cancelled: %s",
+ bus_error_message(&error, r));
return 0;
}
+/* Only a little helper for cleaning up elogind specific extra stuff. */
void elogind_cleanup(void) {
polkit_agent_close();
strv_free(arg_wall);
}
+/* Little debug log helper, helps debugging systemctl comands we mimic. */
static void elogind_log_special(enum elogind_action a) {
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
switch (a) {
case ACTION_HALT:
log_struct(LOG_INFO,
LOG_MESSAGE("Halt action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
NULL);
break;
case ACTION_POWEROFF:
log_struct(LOG_INFO,
LOG_MESSAGE("Poweroff action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
NULL);
break;
case ACTION_REBOOT:
log_struct(LOG_INFO,
LOG_MESSAGE("Reboot action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
NULL);
break;
case ACTION_KEXEC:
log_struct(LOG_INFO,
LOG_MESSAGE("KExec action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
NULL);
break;
case ACTION_SUSPEND:
log_struct(LOG_INFO,
LOG_MESSAGE("Suspend action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+ "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
NULL);
break;
case ACTION_HIBERNATE:
log_struct(LOG_INFO,
LOG_MESSAGE("Hibernate action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+ "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
NULL);
break;
case ACTION_HYBRID_SLEEP:
log_struct(LOG_INFO,
LOG_MESSAGE("Hybrid-Sleep action called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+ "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
+ NULL);
+ break;
+ case ACTION_SUSPEND_THEN_HIBERNATE:
+ log_struct(LOG_INFO,
+ LOG_MESSAGE("Suspend-Then-Hibernate action called."),
+ "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
NULL);
break;
case ACTION_CANCEL_SHUTDOWN:
log_struct(LOG_INFO,
LOG_MESSAGE("Cancel Shutdown called."),
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
NULL);
break;
default:
#endif // ENABLE_DEBUG_ELOGIND
}
+/* Original:
+ * systemctl/systemctl.c:3242:logind_reboot()
+ */
static int elogind_reboot(sd_bus *bus, enum elogind_action a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method = NULL;
+ const char *method = NULL, *description = 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_HALT] = "The system is going down for halt NOW!",
+ [ACTION_REBOOT] = "The system is going down for reboot NOW!",
+ [ACTION_POWEROFF] = "The system is going down for power-off NOW!"
};
if (!bus)
switch (a) {
+ case ACTION_HALT:
+ method = "Halt";
+ description = "halt system";
+ break;
+
case ACTION_POWEROFF:
method = "PowerOff";
+ description = "power off system";
break;
case ACTION_REBOOT:
method = "Reboot";
+ description = "reboot system";
break;
case ACTION_SUSPEND:
method = "Suspend";
+ description = "suspend system";
break;
case ACTION_HIBERNATE:
method = "Hibernate";
+ description = "hibernate system";
break;
case ACTION_HYBRID_SLEEP:
method = "HybridSleep";
+ description = "put system into hybrid sleep";
+ break;
+
+ case ACTION_SUSPEND_THEN_HIBERNATE:
+ method = "SuspendThenHibernate";
+ description = "put system into suspend followed by hibernate";
break;
default:
return -EINVAL;
}
- polkit_agent_open_if_enabled();
+ /* No need for polkit_agent_open_maybe() in elogind. Do it directly. */
+ polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
- if ( IN_SET(a, ACTION_POWEROFF, ACTION_REBOOT) ) {
- r = elogind_set_wall_message(bus, table[a]);
+ if ( IN_SET(a, ACTION_HALT, ACTION_POWEROFF, ACTION_REBOOT) )
+ (void) elogind_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);
- }
- }
+ log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
+
+ if (arg_dry_run)
+ return 0;
/* Now call elogind itself to request the operation */
r = sd_bus_call_method(
"b", arg_ask_password);
if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s via elogind: %s",
+ description,
+ bus_error_message(&error, r));
- return r;
+ return 0;
}
+/* Original:
+ * systemctl/systemctl.c:8553:logind_schedule_shutdown()
+ */
static int elogind_schedule_shutdown(sd_bus *bus, enum elogind_action a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method = NULL;
+ char date[FORMAT_TIMESTAMP_MAX];
+ const char *action;
int r;
if (!bus)
return -EIO;
switch (a) {
-
+ case ACTION_HALT:
+ action = "halt";
+ break;
case ACTION_POWEROFF:
- method = "poweroff";
+ action = "poweroff";
break;
-
- case ACTION_REBOOT:
- method = "reboot";
+ case ACTION_KEXEC:
+ action = "kexec";
break;
-
+ case ACTION_REBOOT:
default:
- return -EINVAL;
+ action = "reboot";
+ break;
}
- r = elogind_set_wall_message(bus, NULL);
+ if (arg_dry_run)
+ action = strjoina("dry-", action);
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
+ (void) elogind_set_wall_message(bus, NULL);
r = sd_bus_call_method(
bus,
&error,
NULL,
"st",
- method,
+ action,
arg_when);
if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_warning_errno(r,
+ "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
+ bus_error_message(&error, r));
+
+ if (!arg_quiet)
+ log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
- return r;
+ return 0;
}
+/* Original:
+ * systemctl/systemctl.c:3204:logind_set_wall_message()
+ * (Tweaked to allow an extra message to be appended.)
+ */
static int elogind_set_wall_message(sd_bus* bus, const char* msg) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *m = NULL;
if (!m)
return log_oom();
+ log_debug("%s wall message \"%s\".", arg_dry_run ? "Would set" : "Setting", m);
+ if (arg_dry_run)
+ return 0;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
return 0;
}
+/* Original:
+ * systemctl/systemctl.c:7743:parse_shutdown_time_spec()
+ */
static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
assert(t);
assert(_u);
return 0;
}
-void polkit_agent_open_if_enabled(void) {
-
- /* Open the polkit agent as a child process if necessary */
-
- if (!arg_ask_password)
- return;
-
- if (arg_transport != BUS_TRANSPORT_LOCAL)
- return;
-
- polkit_agent_open();
-}
-
+/* Original:
+ * systemctl/systemctl.c:3482:start_special()
+ * However, this elogind variant is very different from the original.
+ */
int start_special(int argc, char *argv[], void *userdata) {
sd_bus *bus = userdata;
enum elogind_action a;
ACTION_REBOOT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
- ACTION_HYBRID_SLEEP)) {
+ ACTION_HYBRID_SLEEP,
+ ACTION_SUSPEND_THEN_HIBERNATE)) {
if (arg_when > 0)
return elogind_schedule_shutdown(bus, a);
else