#include "path-util.h"
#include "polkit.h"
#include "special.h"
+#include "systemd/sd-id128.h"
+#include "systemd/sd-messages.h"
#define BUS_MANAGER_INTERFACE \
" <interface name=\"org.freedesktop.login1.Manager\">\n" \
" <method name=\"UnlockSession\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
" </method>\n" \
+ " <method name=\"LockSessions\"/>\n" \
" <method name=\"KillSession\">\n" \
" <arg name=\"id\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
" <property name=\"BlockInhibited\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"DelayInhibited\" type=\"s\" access=\"read\"/>\n" \
" <property name=\"InhibitDelayMaxUSec\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"HandlePowerKey\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"HandleSleepKey\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"HandleLidSwitch\" type=\"s\" access=\"read\"/>\n" \
+ " <property name=\"PreparingForShutdown\" type=\"b\" access=\"read\"/>\n" \
+ " <property name=\"PreparingForSleep\" type=\"b\" access=\"read\"/>\n" \
" </interface>\n"
#define INTROSPECTION_BEGIN \
return 0;
}
+static int bus_manager_append_preparing(DBusMessageIter *i, const char *property, void *data) {
+ Manager *m = data;
+ dbus_bool_t b;
+
+ assert(i);
+ assert(property);
+
+ if (streq(property, "PreparingForShutdown"))
+ b = !!(m->delayed_what & INHIBIT_SHUTDOWN);
+ else
+ b = !!(m->delayed_what & INHIBIT_SLEEP);
+
+ dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b);
+ return 0;
+}
+
static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMessage **_reply) {
Session *session = NULL;
User *user = NULL;
goto finish;
}
- mkdir_p("/etc/udev/rules.d", 0755);
+ mkdir_p_label("/etc/udev/rules.d", 0755);
r = write_one_line_file_atomic(file, rule);
if (r < 0)
goto finish;
DBusMessage *message,
DBusError *error) {
- Session *s;
+ Session *session;
+ Iterator i;
+ unsigned long ul;
assert(m);
- if (hashmap_size(m->sessions) > 1)
- return true;
-
- /* Hmm, there's only one session, but let's make sure it
- * actually belongs to the user who is asking. If not, better
- * be safe than sorry. */
-
- s = hashmap_first(m->sessions);
- if (s) {
- unsigned long ul;
+ ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
+ if (ul == (unsigned long) -1)
+ return -EIO;
- ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
- if (ul == (unsigned long) -1)
- return -EIO;
-
- return s->user->uid != ul;
- }
+ /* Check for other users' sessions. Greeter sessions do not count. */
+ HASHMAP_FOREACH(session, m->sessions, i)
+ if (session->class == SESSION_USER && session->user->uid != ul)
+ return true;
return false;
}
static int send_start_unit(DBusConnection *connection, const char *unit_name, DBusError *error) {
- DBusMessage *message, *reply;
const char *mode = "replace";
- assert(connection);
assert(unit_name);
- message = dbus_message_new_method_call(
+ return bus_method_call_with_reply (
+ connection,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "StartUnit");
- if (!message)
- return -ENOMEM;
-
- if (!dbus_message_append_args(message,
- DBUS_TYPE_STRING, &unit_name,
- DBUS_TYPE_STRING, &mode,
- DBUS_TYPE_INVALID)) {
- dbus_message_unref(message);
- return -ENOMEM;
- }
-
- reply = dbus_connection_send_with_reply_and_block(connection, message, -1, error);
- dbus_message_unref(message);
-
- if (!reply)
- return -EIO;
-
- dbus_message_unref(reply);
- return 0;
+ "StartUnit",
+ NULL,
+ NULL,
+ DBUS_TYPE_STRING, &unit_name,
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
}
static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
if (r < 0)
return r;
- result = "na";
- goto finish;
+ if (r == 0) {
+ result = "na";
+ goto finish;
+ }
}
r = have_multiple_sessions(connection, m, message, error);
if (r > 0)
result = "yes";
- else if (challenge)
- result = "challenge";
- else
- result = "no";
- }
+ else if (challenge)
+ result = "challenge";
+ else
+ result = "no";
+ }
if (blocked) {
r = verify_polkit(connection, message, action_ignore_inhibit, false, &challenge, error);
return 0;
}
+static int bus_manager_log_shutdown(
+ Manager *m,
+ InhibitWhat w,
+ const char *unit_name) {
+
+ const char *p, *q;
+
+ assert(m);
+ assert(unit_name);
+
+ if (w != INHIBIT_SHUTDOWN)
+ return 0;
+
+ if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
+ p = "MESSAGE=System is powering down.";
+ q = "SHUTDOWN=power-off";
+ } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
+ p = "MESSAGE=System is halting.";
+ q = "SHUTDOWN=halt";
+ } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
+ p = "MESSAGE=System is rebooting.";
+ q = "SHUTDOWN=reboot";
+ } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
+ p = "MESSAGE=System is rebooting with kexec.";
+ q = "SHUTDOWN=kexec";
+ } else {
+ p = "MESSAGE=System is shutting down.";
+ q = NULL;
+ }
+
+ return log_struct(LOG_NOTICE,
+ "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_SHUTDOWN),
+ p,
+ q, NULL);
+}
+
+int bus_manager_shutdown_or_sleep_now_or_later(
+ Manager *m,
+ const char *unit_name,
+ InhibitWhat w,
+ DBusError *error) {
+
+ bool delayed;
+ int r;
+
+ assert(m);
+ assert(unit_name);
+ assert(w >= 0);
+ assert(w <= _INHIBIT_WHAT_MAX);
+
+ delayed =
+ m->inhibit_delay_max > 0 &&
+ manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
+
+ if (delayed)
+ /* Shutdown is delayed, keep in mind what we
+ * want to do, and start a timeout */
+ r = delay_shutdown_or_sleep(m, w, unit_name);
+ else {
+ bus_manager_log_shutdown(m, w, unit_name);
+
+ /* Shutdown is not delayed, execute it
+ * immediately */
+ r = send_start_unit(m->bus, unit_name, error);
+ }
+
+ return r;
+}
+
static int bus_manager_do_shutdown_or_sleep(
Manager *m,
DBusConnection *connection,
DBusMessage **_reply) {
dbus_bool_t interactive;
- bool multiple_sessions, blocked, delayed;
+ bool multiple_sessions, blocked;
DBusMessage *reply = NULL;
int r;
return r;
}
- delayed =
- m->inhibit_delay_max > 0 &&
- manager_is_inhibited(m, w, INHIBIT_DELAY, NULL);
-
- if (delayed) {
- /* Shutdown is delayed, keep in mind what we
- * want to do, and start a timeout */
- r = delay_shutdown_or_sleep(m, w, unit_name);
- } else
- /* Shutdown is not delayed, execute it
- * immediately */
- r = send_start_unit(connection, unit_name, error);
-
+ r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
if (r < 0)
return r;
return 0;
}
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_handle_button, handle_button, HandleButton);
+
static const BusProperty bus_login_manager_properties[] = {
{ "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_path), true },
{ "Controllers", bus_property_append_strv, "as", offsetof(Manager, controllers), true },
{ "BlockInhibited", bus_manager_append_inhibited, "s", 0 },
{ "DelayInhibited", bus_manager_append_inhibited, "s", 0 },
{ "InhibitDelayMaxUSec", bus_property_append_usec, "t", offsetof(Manager, inhibit_delay_max) },
+ { "HandlePowerKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_power_key) },
+ { "HandleSleepKey", bus_manager_append_handle_button, "s", offsetof(Manager, handle_sleep_key) },
+ { "HandleLidSwitch", bus_manager_append_handle_button, "s", offsetof(Manager, handle_lid_switch) },
+ { "PreparingForShutdown", bus_manager_append_preparing, "b", 0 },
+ { "PreparingForSleep", bus_manager_append_preparing, "b", 0 },
{ NULL, }
};
if (!reply)
goto oom;
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "LockSessions")) {
+ Session *session;
+ Iterator i;
+
+ HASHMAP_FOREACH(session, m->sessions, i)
+ if (session_send_lock(session, true) < 0)
+ goto oom;
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ goto oom;
+
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "KillSession")) {
const char *swho;
int32_t signo;
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
- mkdir_p("/var/lib/systemd", 0755);
+ mkdir_p_label("/var/lib/systemd", 0755);
- r = safe_mkdir("/var/lib/systemd/linger", 0755, 0, 0);
+ r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
if (delayed)
return 0;
+ bus_manager_log_shutdown(manager, manager->delayed_what, manager->delayed_unit);
+
/* Reset delay data */
unit_name = manager->delayed_unit;
manager->delayed_unit = NULL;