-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include "audit-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
+//#include "bus-unit-util.h"
#include "bus-util.h"
#include "dirent-util.h"
//#include "efivars.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio-label.h"
-#include "formats-util.h"
+#include "format-util.h"
#include "fs-util.h"
#include "logind.h"
#include "mkdir.h"
#include "path-util.h"
#include "process-util.h"
+//#include "cgroup-util.h"
#include "selinux-util.h"
#include "sleep-config.h"
//#include "special.h"
#include "udev-util.h"
#include "unit-name.h"
#include "user-util.h"
-//#include "utmp-wtmp.h"
+#include "utmp-wtmp.h"
-int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+/// Additional includes needed by elogind
+#include "elogind-dbus.h"
+
+static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
+
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ const char *name;
Session *session;
int r;
+ /* Get client login session. This is not what you are looking for these days,
+ * as apps may instead belong to a user service unit. This includes terminal
+ * emulators and hence command-line apps. */
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_session(creds, &name);
+ if (r == -ENXIO)
+ goto err_no_session;
+ if (r < 0)
+ return r;
+
+ session = hashmap_get(m->sessions, name);
+ if (!session)
+ goto err_no_session;
+
+ *ret = session;
+ return 0;
+
+err_no_session:
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
+ "Caller does not belong to any known session");
+}
+
+int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
+ Session *session;
+
assert(m);
assert(message);
assert(ret);
- if (isempty(name)) {
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_session(creds, &name);
- if (r < 0)
- return r;
- }
+ if (isempty(name))
+ return get_sender_session(m, message, error, ret);
session = hashmap_get(m->sessions, name);
if (!session)
return 0;
}
-int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
+static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *error, User **ret) {
+
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ uid_t uid;
User *user;
int r;
+ /* Note that we get the owner UID of the session, not the actual client UID here! */
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_owner_uid(creds, &uid);
+ if (r == -ENXIO)
+ goto err_no_user;
+ if (r < 0)
+ return r;
+
+ user = hashmap_get(m->users, UID_TO_PTR(uid));
+ if (!user)
+ goto err_no_user;
+
+ *ret = user;
+ return 0;
+
+err_no_user:
+ return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "Caller does not belong to any logged in user or lingering user");
+}
+
+int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
+ User *user;
+
assert(m);
assert(message);
assert(ret);
- if (uid == UID_INVALID) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-
- /* Note that we get the owner UID of the session, not the actual client UID here! */
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_owner_uid(creds, &uid);
- if (r < 0)
- return r;
- }
+ if (!uid_is_valid(uid))
+ return get_sender_user(m, message, error, ret);
user = hashmap_get(m->users, UID_TO_PTR(uid));
if (!user)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "No user "UID_FMT" known or logged in", uid);
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "User ID "UID_FMT" is not logged in or lingering", uid);
*ret = user;
return 0;
return r;
seat = session->seat;
-
if (!seat)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat.");
} else {
assert(m);
if (streq(property, "PreparingForShutdown"))
- b = !!(m->action_what & INHIBIT_SHUTDOWN);
+ b = m->action_what & INHIBIT_SHUTDOWN;
else
- b = !!(m->action_what & INHIBIT_SLEEP);
+ b = m->action_what & INHIBIT_SLEEP;
return sd_bus_message_append(reply, "b", b);
}
}
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction);
-
-static int property_get_docked(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
-}
+static BUS_DEFINE_PROPERTY_GET(property_get_docked, "b", Manager, manager_is_docked_or_external_displays);
+static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_compat_user_tasks_max, "t", CGROUP_LIMIT_MAX);
+static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "t", Hashmap *, (uint64_t) hashmap_size);
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
return sd_bus_reply_method_return(message, "o", p);
}
+/* Get login session of a process. This is not what you are looking for these days,
+ * as apps may instead belong to a user service unit. This includes terminal
+ * emulators and hence command-line apps. */
static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Session *session = NULL;
if (r < 0)
return r;
if (!user)
- return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "PID "PID_FMT" does not belong to any known or logged in user", pid);
+ return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
+ "PID "PID_FMT" does not belong to any logged in user or lingering user",
+ pid);
}
p = user_bus_path(user);
}
static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
Session *session;
Iterator i;
}
static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
User *user;
Iterator i;
}
static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
Seat *seat;
Iterator i;
}
static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
Inhibitor *inhibitor;
Iterator i;
static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
- uint32_t audit_id = 0;
_cleanup_free_ char *id = NULL;
Session *session = NULL;
+ uint32_t audit_id = 0;
Manager *m = userdata;
User *user = NULL;
Seat *seat = NULL;
if (!uid_is_valid(uid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
- if (leader < 0 || leader == 1)
+ if (leader < 0 || leader == 1 || leader == getpid_cached())
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (isempty(type))
if (v <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
- if (!vtnr)
+ if (vtnr == 0)
vtnr = (uint32_t) v;
else if (vtnr != (uint32_t) v)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
if (seat) {
if (seat_has_vts(seat)) {
- if (!vtnr || vtnr > 63)
+ if (vtnr <= 0 || vtnr > 63)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
} else {
if (vtnr != 0)
}
}
- r = sd_bus_message_enter_container(message, 'a', "(sv)");
- if (r < 0)
- return r;
-
if (t == _SESSION_TYPE_INVALID) {
if (!isempty(display))
t = SESSION_X11;
}
if (leader == 0) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
if (r < 0)
return r;
}
- r = manager_get_session_by_pid(m, leader, NULL);
+ /* Check if we are already in a logind session. Or if we are in user@.service which is a special PAM session
+ * that avoids creating a logind session. */
+ r = manager_get_user_by_pid(m, leader, NULL);
+ if (r < 0)
+ return r;
if (r > 0)
- return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session");
+ return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
/*
* Old gdm and lightdm start the user-session on the same VT as
m->seat0->positions[vtnr]->class != SESSION_GREETER)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
- audit_session_from_pid(leader, &audit_id);
- if (audit_id > 0) {
+ if (hashmap_size(m->sessions) >= m->sessions_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
+
+ (void) audit_session_from_pid(leader, &audit_id);
+ if (audit_session_is_valid(audit_id)) {
/* Keep our session IDs and the audit session IDs in sync */
if (asprintf(&id, "%"PRIu32, audit_id) < 0)
* the audit data and let's better register a new
* ID */
if (hashmap_get(m->sessions, id)) {
- log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
- audit_id = 0;
-
+ log_warning("Existing logind session ID %s used by new audit session, ignoring.", id);
+ audit_id = AUDIT_SESSION_INVALID;
id = mfree(id);
}
}
goto fail;
}
- r = session_start(session);
+ r = sd_bus_message_enter_container(message, 'a', "(sv)");
+ if (r < 0)
+ return r;
+
+ r = session_start(session, message);
+ if (r < 0)
+ goto fail;
+
+ r = sd_bus_message_exit_container(message);
if (r < 0)
goto fail;
session->create_message = sd_bus_message_ref(message);
- /* Here upstream systemd starts cgroups and the user systemd,
- and arranges to reply asynchronously. We reply
- directly. */
+#if 0 /// UNNEEDED by elogind
+ /* Now, let's wait until the slice unit and stuff got created. We send the reply back from
+ * session_send_create_reply(). */
+#else
+ /* We reply directly. */
r = session_send_create_reply(session, NULL);
if (r < 0)
goto fail;
+#endif // 0
return 1;
if (r < 0)
return r;
+#if 1 /// elogind must queue this session
session_add_to_gc_queue(session);
-
+#endif // 1
return sd_bus_reply_method_return(message, NULL);
}
}
static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
_cleanup_free_ char *cc = NULL;
Manager *m = userdata;
- int b, r;
+ int r, b, interactive;
struct passwd *pw;
const char *path;
- uint32_t uid;
- int interactive;
+ uint32_t uid, auth_uid;
assert(message);
assert(m);
if (r < 0)
return r;
- if (uid == UID_INVALID) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-
- /* Note that we get the owner UID of the session, not the actual client UID here! */
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
- if (r < 0)
- return r;
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID |
+ SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds);
+ if (r < 0)
+ return r;
+ if (!uid_is_valid(uid)) {
+ /* Note that we get the owner UID of the session or user unit,
+ * not the actual client UID here! */
r = sd_bus_creds_get_owner_uid(creds, &uid);
if (r < 0)
return r;
+ }
- } else if (!uid_is_valid(uid))
- return -EINVAL;
+ /* owner_uid is racy, so for authorization we must use euid */
+ r = sd_bus_creds_get_euid(creds, &auth_uid);
+ if (r < 0)
+ return r;
errno = 0;
pw = getpwuid(uid);
if (!pw)
- return errno ? -errno : -ENOENT;
+ return errno > 0 ? -errno : -ENOENT;
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-user-linger",
+ uid == auth_uid ? "org.freedesktop.login1.set-self-linger" :
+ "org.freedesktop.login1.set-user-linger",
NULL,
interactive,
UID_INVALID,
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- mkdir_p_label("/var/lib/systemd", 0755);
+ mkdir_p_label("/var/lib/elogind", 0755);
- r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0);
+ r = mkdir_safe_label("/var/lib/elogind/linger", 0755, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
return r;
if (!cc)
return -ENOMEM;
- path = strjoina("/var/lib/systemd/linger/", cc);
+ path = strjoina("/var/lib/elogind/linger/", cc);
if (b) {
User *u;
}
static int trigger_device(Manager *m, struct udev_device *d) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
+ _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL;
struct udev_list_entry *first, *item;
int r;
if (!t)
return -ENOMEM;
- write_string_file(t, "change", WRITE_STRING_FILE_CREATE);
+ (void) write_string_file(t, "change", 0);
}
return 0;
}
static int attach_device(Manager *m, const char *seat, const char *sysfs) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_(udev_device_unrefp) struct udev_device *d = NULL;
_cleanup_free_ char *rule = NULL, *file = NULL;
const char *id_for_seat;
int r;
return -ENOMEM;
mkdir_p_label("/etc/udev/rules.d", 0755);
- mac_selinux_init("/etc");
r = write_string_file_atomic_label(file, rule);
if (r < 0)
return r;
} else {
struct dirent *de;
- while ((de = readdir(d))) {
-
+ FOREACH_DIRENT_ALL(de, d, break) {
if (!dirent_is_file(de))
continue;
return false;
}
+#if 0 /// elogind has its own variant in elogind-dbus.c
static int bus_manager_log_shutdown(
Manager *m,
- InhibitWhat w,
-#if 0 /// elogind does not support systemd units
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_HALT_TARGET)) {
+ p = "MESSAGE=System is halting";
+ q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec";
p = "MESSAGE=System is shutting down";
q = NULL;
}
-#else
- HandleAction action) {
-
- const char *p, *q;
-
- assert(m);
-
- if (w != INHIBIT_SHUTDOWN)
- return 0;
-
- switch (action) {
- case HANDLE_POWEROFF:
- p = "MESSAGE=System is powering down.";
- q = "SHUTDOWN=power-off";
- break;
- case HANDLE_HALT:
- p = "MESSAGE=System is halting.";
- q = "SHUTDOWN=halt";
- break;
- case HANDLE_REBOOT:
- p = "MESSAGE=System is rebooting.";
- q = "SHUTDOWN=reboot";
- break;
- case HANDLE_KEXEC:
- p = "MESSAGE=System is rebooting with kexec.";
- q = "SHUTDOWN=kexec";
- break;
- default:
- p = "MESSAGE=System is shutting down.";
- q = NULL;
- }
-#endif // 0
+
if (isempty(m->wall_message))
p = strjoina(p, ".");
else
p = strjoina(p, " (", m->wall_message, ").");
return log_struct(LOG_NOTICE,
- LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
p,
- q,
- NULL);
+ q);
}
+#endif // 0
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
Manager *m = userdata;
return r;
}
-static void reset_scheduled_shutdown(Manager *m) {
- m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
- m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
- m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
- m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
- m->scheduled_shutdown_timeout = 0;
- m->shutdown_dry_run = false;
+#if 0 /// elogind-dbus.c needs to access this
+static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
+#else
+int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
+#endif // 0
- if (m->unlink_nologin) {
- (void) unlink("/run/nologin");
- m->unlink_nologin = false;
- }
+ static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
+ [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
+ [INHIBIT_SLEEP] = "PrepareForSleep"
+ };
+
+ int active = _active;
+
+ assert(m);
+ assert(w >= 0);
+ assert(w < _INHIBIT_WHAT_MAX);
+ assert(signal_name[w]);
+
+ return sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ signal_name[w],
+ "b",
+ active);
}
+#if 0 /// elogind has its own variant in elogind-dbus.c
static int execute_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
- HandleAction action,
+ const char *unit_name,
sd_bus_error *error) {
-#if 0 /// elogind does not need these, we do it ourselves
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
char *c = NULL;
const char *p;
-#endif // 0
int r;
assert(m);
- assert(w >= 0);
+ assert(w > 0);
assert(w < _INHIBIT_WHAT_MAX);
+ assert(unit_name);
- bus_manager_log_shutdown(m, w, action);
+ if (w == INHIBIT_SHUTDOWN)
+ bus_manager_log_shutdown(m, unit_name);
-#if 0 /// elogind does it directly without depending on systemd running the system
- if (m->shutdown_dry_run) {
- log_info("Running in dry run, suppressing action.");
- reset_scheduled_shutdown(m);
- } else {
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"StartUnit",
error,
&reply,
- "ss", NULL, "replace-irreversibly");
-#else
- r = shutdown_or_sleep(m, action);
-
- /* no more pending actions, whether this failed or not */
- m->pending_action = HANDLE_IGNORE;
- m->action_what = 0;
-#endif // 0
+ "ss", unit_name, "replace-irreversibly");
if (r < 0)
- return r;
+ goto error;
-#if 0 /// elogind neither needs a dbus reply, nor supports systemd action jobs
r = sd_bus_message_read(reply, "o", &p);
if (r < 0)
- return r;
+ goto error;
c = strdup(p);
- if (!c)
- return -ENOMEM;
+ if (!c) {
+ r = -ENOMEM;
+ goto error;
}
m->action_unit = unit_name;
free(m->action_job);
m->action_job = c;
m->action_what = w;
-#endif // 0
/* Make sure the lid switch is ignored for a while */
manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
return 0;
+
+error:
+ /* Tell people that they now may take a lock again */
+ (void) send_prepare_for(m, w, false);
+
+ return r;
}
+#endif // 0
int manager_dispatch_delayed(Manager *manager, bool timeout) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
Inhibitor *offending = NULL;
int r;
assert(manager);
+#if 0 /// elogind has no action_job, but a pending_action
+ if (manager->action_what == 0 || manager->action_job)
+#else
if ( (0 == manager->action_what) || (HANDLE_IGNORE == manager->pending_action) )
+#endif // 0
return 0;
if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
}
/* Actually do the operation */
+#if 0 /// elogind has no action_unit but a pending_action
+ r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
+#else
r = execute_shutdown_or_sleep(manager, manager->action_what, manager->pending_action, &error);
+#endif // 0
if (r < 0) {
- log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
+ log_warning("Error during inhibitor-delayed operation (already returned success to client): %s",
+ bus_error_message(&error, r));
+
+#if 0 /// elogind has no action_unit but a pending_action
+ manager->action_unit = NULL;
+ manager->action_what = 0;
+ return r;
+#else
manager->pending_action = HANDLE_IGNORE;
manager->action_what = 0;
- return r;
+ /* It is not a critical error for elogind if suspending fails */
+#endif // 0
}
return 1;
return (r < 0) ? r : 0;
}
+#if 0 /// elogind does not have unit_name but action
static int delay_shutdown_or_sleep(
Manager *m,
InhibitWhat w,
- HandleAction action) {
+ const char *unit_name) {
+#else
+int delay_shutdown_or_sleep(
+ Manager *m,
+ InhibitWhat w,
+ HandleAction action) {
+#endif // 0
int r;
usec_t timeout_val;
assert(m);
assert(w >= 0);
assert(w < _INHIBIT_WHAT_MAX);
+#if 0 /// UNNEEDED by elogind
+ assert(unit_name);
+#endif // 0
timeout_val = now(CLOCK_MONOTONIC) + m->inhibit_delay_max;
return r;
}
+#if 0 /// elogind does not have unit_name but pendig_action
+ m->action_unit = unit_name;
+#else
m->pending_action = action;
+#endif // 0
m->action_what = w;
return 0;
}
-static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
-
- static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
- [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
- [INHIBIT_SLEEP] = "PrepareForSleep"
- };
-
- int active = _active;
-
- assert(m);
- assert(w >= 0);
- assert(w < _INHIBIT_WHAT_MAX);
- assert(signal_name[w]);
-
- return sd_bus_emit_signal(m->bus,
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- signal_name[w],
- "b",
- active);
-}
-
int bus_manager_shutdown_or_sleep_now_or_later(
Manager *m,
- HandleAction action,
+#if 0 /// elogind has HandleAction instead of const char* unit_name
+ const char *unit_name,
+
+ _cleanup_free_ char *load_state = NULL;
+#else
+ HandleAction unit_name,
+#endif // 0
InhibitWhat w,
sd_bus_error *error) {
-
bool delayed;
int r;
assert(m);
- assert(w >= 0);
+#if 0 /// for elogind only w has to be checked.
+ assert(unit_name);
+ assert(w > 0);
assert(w <= _INHIBIT_WHAT_MAX);
+ assert(!m->action_job);
+
+ r = unit_load_state(m->bus, unit_name, &load_state);
+ if (r < 0)
+ return r;
+
+ if (!streq(load_state, "loaded")) {
+ log_notice("Unit %s is %s, refusing operation.", unit_name, load_state);
+ return -EACCES;
+ }
+#else
+ assert(w > 0);
+ assert(w <= _INHIBIT_WHAT_MAX);
+#endif // 0
/* Tell everybody to prepare for shutdown/sleep */
- send_prepare_for(m, w, true);
+ (void) send_prepare_for(m, w, true);
delayed =
m->inhibit_delay_max > 0 &&
manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
+ log_debug_elogind("%s called for %s (%sdelayed)", __FUNCTION__,
+ handle_action_to_string(unit_name),
+ delayed ? "" : "NOT ");
if (delayed)
/* Shutdown is delayed, keep in mind what we
* want to do, and start a timeout */
- r = delay_shutdown_or_sleep(m, w, action);
+ r = delay_shutdown_or_sleep(m, w, unit_name);
else
/* Shutdown is not delayed, execute it
* immediately */
- r = execute_shutdown_or_sleep(m, w, action, error);
+ r = execute_shutdown_or_sleep(m, w, unit_name, error);
return r;
}
const char *action_ignore_inhibit,
sd_bus_error *error) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
bool multiple_sessions, blocked;
uid_t uid;
int r;
static int method_do_shutdown_or_sleep(
Manager *m,
sd_bus_message *message,
- HandleAction sleep_action,
+#if 0 /// elogind has HandleAction instead of const char* unit_name
+ const char *unit_name,
+#else
+ HandleAction unit_name,
+#endif // 0
InhibitWhat w,
const char *action,
const char *action_multiple_sessions,
assert(m);
assert(message);
+#if 0 /// elogind does not need this to be checked
+ assert(unit_name);
+#endif // 0
assert(w >= 0);
assert(w <= _INHIBIT_WHAT_MAX);
if (r < 0)
return r;
+ log_debug_elogind("%s called with action '%s', sleep '%s' (%sinteractive)",
+ __FUNCTION__, action, sleep_verb,
+ interactive ? "" : "NOT ");
/* Don't allow multiple jobs being executed at the same time */
if (m->action_what)
return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
if (sleep_verb) {
+#if 0 /// Within elogind the manager m must be provided, too
r = can_sleep(sleep_verb);
+ if (r == -ENOSPC)
+ return sd_bus_error_set(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Not enough swap space for hibernation");
+ if (r == 0)
+ return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
+ "Sleep verb \"%s\" not supported", sleep_verb);
+#else
+ r = can_sleep(m, sleep_verb);
+#endif // 0
if (r < 0)
return r;
-
- if (r == 0)
- return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
}
+#if 0 /// Within elogind it does not make sense to verify shutdown creds when suspending
r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
action_ignore_inhibit, error);
if (r != 0)
return r;
+#else
+ if (IN_SET(unit_name, HANDLE_HALT, HANDLE_POWEROFF, HANDLE_REBOOT)) {
+ r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
+ action_ignore_inhibit, error);
+ log_debug_elogind("verify_shutdown_creds() returned %d", r);
+ if (r != 0)
+ return r;
+ }
+#endif // 0
- r = bus_manager_shutdown_or_sleep_now_or_later(m, sleep_action, w, error);
+ r = bus_manager_shutdown_or_sleep_now_or_later(m, unit_name, w, error);
if (r < 0)
return r;
static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
+ log_debug_elogind("%s called", __FUNCTION__);
return method_do_shutdown_or_sleep(
m, message,
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_POWEROFF_TARGET,
+#else
HANDLE_POWEROFF,
+#endif // 0
INHIBIT_SHUTDOWN,
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
+ log_debug_elogind("%s called", __FUNCTION__);
return method_do_shutdown_or_sleep(
m, message,
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_REBOOT_TARGET,
+#else
HANDLE_REBOOT,
+#endif // 0
INHIBIT_SHUTDOWN,
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
error);
}
-static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
+ log_debug_elogind("%s called", __FUNCTION__);
return method_do_shutdown_or_sleep(
m, message,
- HANDLE_SUSPEND,
- INHIBIT_SLEEP,
- "org.freedesktop.login1.suspend",
- "org.freedesktop.login1.suspend-multiple-sessions",
- "org.freedesktop.login1.suspend-ignore-inhibit",
- "suspend",
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_HALT_TARGET,
+#else
+ HANDLE_HALT,
+#endif // 0
+ INHIBIT_SHUTDOWN,
+ "org.freedesktop.login1.halt",
+ "org.freedesktop.login1.halt-multiple-sessions",
+ "org.freedesktop.login1.halt-ignore-inhibit",
+ NULL,
+ error);
+}
+
+static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ log_debug_elogind("%s called", __FUNCTION__);
+ return method_do_shutdown_or_sleep(
+ m, message,
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_SUSPEND_TARGET,
+#else
+ HANDLE_SUSPEND,
+#endif // 0
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.suspend",
+ "org.freedesktop.login1.suspend-multiple-sessions",
+ "org.freedesktop.login1.suspend-ignore-inhibit",
+ "suspend",
+ error);
+}
+
+static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ log_debug_elogind("%s called", __FUNCTION__);
+ return method_do_shutdown_or_sleep(
+ m, message,
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_HIBERNATE_TARGET,
+#else
+ HANDLE_HIBERNATE,
+#endif // 0
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "hibernate",
+ error);
+}
+
+static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ log_debug_elogind("%s called", __FUNCTION__);
+ return method_do_shutdown_or_sleep(
+ m, message,
+#if 0 /// elogind uses HandleAction instead of const char* unti names
+ SPECIAL_HYBRID_SLEEP_TARGET,
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "hybrid-sleep",
+ error);
+}
+
+static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_do_shutdown_or_sleep(
+ m, message,
+ SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
+#else
+ HANDLE_HYBRID_SLEEP,
+#endif // 0
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "hybrid-sleep",
error);
}
void *userdata) {
Manager *m = userdata;
- int r;
log_info("Creating /run/nologin, blocking further logins...");
- r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
- if (r < 0)
- log_error_errno(r, "Failed to create /run/nologin: %m");
- else
- m->unlink_nologin = true;
+ m->unlink_nologin =
+ create_shutdown_run_nologin_or_warn() >= 0;
return 0;
}
assert(m);
- r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
+ r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0, MKDIR_WARN_MODE);
if (r < 0)
return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
return 0;
fail:
- (void) unlink(temp_path);
- (void) unlink("/run/systemd/shutdown/scheduled");
+ (void) unlink(temp_path);
+ (void) unlink("/run/systemd/shutdown/scheduled");
return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
}
+#if 0 /// elogind must access this from elogind-dbus.c
+static void reset_scheduled_shutdown(Manager *m) {
+#else
+void reset_scheduled_shutdown(Manager *m) {
+#endif // 0
+ assert(m);
+
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
+
+ m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
+ m->scheduled_shutdown_timeout = 0;
+ m->shutdown_dry_run = false;
+
+ if (m->unlink_nologin) {
+ (void) unlink_or_warn("/run/nologin");
+ m->unlink_nologin = false;
+ }
+
+ (void) unlink("/run/systemd/shutdown/scheduled");
+}
+
+#if 0 /// elogind has its own variant in elogind-dbus.c
static int manager_scheduled_shutdown_handler(
sd_event_source *s,
uint64_t usec,
void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
Manager *m = userdata;
- HandleAction action;
+ const char *target;
int r;
assert(m);
if (isempty(m->scheduled_shutdown_type))
return 0;
- if (streq(m->scheduled_shutdown_type, "halt"))
- action = HANDLE_HALT;
- else if (streq(m->scheduled_shutdown_type, "poweroff"))
- action = HANDLE_POWEROFF;
+ if (streq(m->scheduled_shutdown_type, "poweroff"))
+ target = SPECIAL_POWEROFF_TARGET;
+ else if (streq(m->scheduled_shutdown_type, "reboot"))
+ target = SPECIAL_REBOOT_TARGET;
+ else if (streq(m->scheduled_shutdown_type, "halt"))
+ target = SPECIAL_HALT_TARGET;
else
- action = HANDLE_REBOOT;
+ assert_not_reached("unexpected shutdown type");
- r = execute_shutdown_or_sleep(m, 0, action, &error);
- if (r < 0)
- return log_error_errno(r, "Unable to execute transition to %s: %m", m->scheduled_shutdown_type);
+ /* Don't allow multiple jobs being executed at the same time */
+ if (m->action_what) {
+ r = -EALREADY;
+ log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target);
+ goto error;
+ }
+
+ if (m->shutdown_dry_run) {
+ /* We do not process delay inhibitors here. Otherwise, we
+ * would have to be considered "in progress" (like the check
+ * above) for some seconds after our admin has seen the final
+ * wall message. */
+
+ bus_manager_log_shutdown(m, target);
+ log_info("Running in dry run, suppressing action.");
+ reset_scheduled_shutdown(m);
+
+ return 0;
+ }
+
+ r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error);
+ if (r < 0) {
+ log_error_errno(r, "Scheduled shutdown to %s failed: %m", target);
+ goto error;
+ }
return 0;
+
+error:
+ reset_scheduled_shutdown(m);
+ return r;
}
+#endif // 0
static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *action_multiple_sessions = NULL;
const char *action_ignore_inhibit = NULL;
const char *action = NULL;
uint64_t elapse;
char *type;
int r;
+ bool dry_run = false;
assert(m);
assert(message);
+ log_debug_elogind("%s called", __FUNCTION__);
r = sd_bus_message_read(message, "st", &type, &elapse);
if (r < 0)
return r;
if (startswith(type, "dry-")) {
type += 4;
- m->shutdown_dry_run = true;
+ dry_run = true;
}
- if (streq(type, "reboot")) {
+ if (streq(type, "poweroff")) {
+ action = "org.freedesktop.login1.power-off";
+ action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
+ action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
+ } else if (streq(type, "reboot")) {
action = "org.freedesktop.login1.reboot";
action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
action = "org.freedesktop.login1.halt";
action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
- } else if (streq(type, "poweroff")) {
- action = "org.freedesktop.login1.poweroff";
- action_multiple_sessions = "org.freedesktop.login1.poweroff-multiple-sessions";
- action_ignore_inhibit = "org.freedesktop.login1.poweroff-ignore-inhibit";
} else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
return log_oom();
}
+ m->shutdown_dry_run = dry_run;
+
if (m->nologin_timeout_source) {
r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
if (r < 0)
}
}
-#if 0 /// elogind does not support utmp-wtmp
r = manager_setup_wall_message_timer(m);
if (r < 0)
return r;
-#endif // 0
- if (!isempty(type)) {
- r = update_schedule_file(m);
- if (r < 0)
- return r;
- } else
- (void) unlink("/run/systemd/shutdown/scheduled");
+ r = update_schedule_file(m);
+ if (r < 0)
+ return r;
return sd_bus_reply_method_return(message, NULL);
}
static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
bool cancelled;
+#if 1 /// elogind needs to construct the message to allow extra wall messages
+ _cleanup_free_ char *l = NULL;
+#endif // 1
assert(m);
assert(message);
+ log_debug_elogind("%s called", __FUNCTION__);
cancelled = m->scheduled_shutdown_type != NULL;
reset_scheduled_shutdown(m);
-#if 0 /// elogind does not support utmp-wtmp
- if (cancelled) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ if (cancelled && m->enable_wall_messages) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *tty = NULL;
uid_t uid = 0;
int r;
(void) sd_bus_creds_get_tty(creds, &tty);
}
+#if 0 /// elogind wants to allow extra cancellation messages
utmp_wall("The system shutdown has been cancelled",
uid_to_name(uid), tty, logind_wall_tty_filter, m);
- }
+#else
+ r = asprintf(&l, "%s%sThe system shutdown has been cancelled!",
+ strempty(m->wall_message),
+ isempty(m->wall_message) ? "" : "\n");
+ if (r < 0) {
+ log_oom();
+ return 0;
+ }
+
+ utmp_wall(l, uid_to_name(uid), tty, logind_wall_tty_filter, m);
#endif // 0
+ }
return sd_bus_reply_method_return(message, "b", cancelled);
}
-static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
-
- return method_do_shutdown_or_sleep(
- m, message,
- HANDLE_HIBERNATE,
- INHIBIT_SLEEP,
- "org.freedesktop.login1.hibernate",
- "org.freedesktop.login1.hibernate-multiple-sessions",
- "org.freedesktop.login1.hibernate-ignore-inhibit",
- "hibernate",
- error);
-}
-
-static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
-
- return method_do_shutdown_or_sleep(
- m, message,
- HANDLE_HYBRID_SLEEP,
- INHIBIT_SLEEP,
- "org.freedesktop.login1.hibernate",
- "org.freedesktop.login1.hibernate-multiple-sessions",
- "org.freedesktop.login1.hibernate-ignore-inhibit",
- "hybrid-sleep",
- error);
-}
-
static int method_can_shutdown_or_sleep(
Manager *m,
sd_bus_message *message,
const char *sleep_verb,
sd_bus_error *error) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ HandleAction handle;
bool multiple_sessions, challenge, blocked;
const char *result = NULL;
uid_t uid;
assert(action_ignore_inhibit);
if (sleep_verb) {
+#if 0 /// elogind needs to have the manager being passed
r = can_sleep(sleep_verb);
+ if (IN_SET(r, 0, -ENOSPC))
+ return sd_bus_reply_method_return(message, "s", "na");
+#else
+ r = can_sleep(m, sleep_verb);
+#endif // 0
if (r < 0)
return r;
- if (r == 0)
- return sd_bus_reply_method_return(message, "s", "na");
}
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
multiple_sessions = r > 0;
blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL);
+ handle = handle_action_from_string(sleep_verb);
+ if (handle >= 0) {
+ const char *target;
+
+ target = manager_target_for_action(handle);
+ if (target) {
+ _cleanup_free_ char *load_state = NULL;
+
+ r = unit_load_state(m->bus, target, &load_state);
+ if (r < 0)
+ return r;
+
+ if (!streq(load_state, "loaded")) {
+ result = "no";
+ goto finish;
+ }
+ }
+ }
+
if (multiple_sessions) {
r = bus_test_polkit(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, UID_INVALID, &challenge, error);
if (r < 0)
result = "no";
}
+ finish:
return sd_bus_reply_method_return(message, "s", result);
}
error);
}
+static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_can_shutdown_or_sleep(
+ m, message,
+ INHIBIT_SHUTDOWN,
+ "org.freedesktop.login1.halt",
+ "org.freedesktop.login1.halt-multiple-sessions",
+ "org.freedesktop.login1.halt-ignore-inhibit",
+ NULL,
+ error);
+}
+
static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
error);
}
+static int method_can_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_can_shutdown_or_sleep(
+ m, message,
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "suspend-then-hibernate",
+ error);
+}
+
static int property_get_reboot_to_firmware_setup(
sd_bus *bus,
const char *path,
r = efi_get_reboot_to_firmware();
if (r < 0 && r != -EOPNOTSUPP)
- return r;
+ log_warning_errno(r, "Failed to determine reboot-to-firmware state: %m");
return sd_bus_message_append(reply, "b", r > 0);
#else
- return sd_bus_message_append(reply, "b", -EOPNOTSUPP);
+ return sd_bus_message_append(reply, "b", false);
#endif // 0
}
assert(m);
r = efi_reboot_to_firmware_supported();
- if (r == -EOPNOTSUPP)
+ if (r < 0) {
+ if (r != -EOPNOTSUPP)
+ log_warning_errno(errno, "Failed to determine whether reboot to firmware is supported: %m");
+
return sd_bus_reply_method_return(message, "s", "na");
- else if (r < 0)
- return r;
+ }
r = bus_test_polkit(message,
CAP_SYS_ADMIN,
return sd_bus_reply_method_return(message, "s", result);
#else
- return sd_bus_reply_method_return(message, "s", "na");
+ return sd_bus_reply_method_return(message, "s", "no");
#endif // 0
}
int r;
Manager *m = userdata;
char *wall_message;
- int enable_wall_messages;
+ unsigned enable_wall_messages;
assert(message);
assert(m);
if (r < 0)
return r;
+#if 0 /// elogind only calls this for shutdown/reboot, which already needs authorization.
r = bus_verify_polkit_async(message,
CAP_SYS_ADMIN,
"org.freedesktop.login1.set-wall-message",
return r;
if (r == 0)
return 1; /* Will call us back */
+#endif // 0
- if (isempty(wall_message))
- m->wall_message = mfree(m->wall_message);
- else {
- r = free_and_strdup(&m->wall_message, wall_message);
- if (r < 0)
- return log_oom();
- }
+ r = free_and_strdup(&m->wall_message, empty_to_null(wall_message));
+ if (r < 0)
+ return log_oom();
m->enable_wall_messages = enable_wall_messages;
}
static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
const char *who, *why, *what, *mode;
_cleanup_free_ char *id = NULL;
_cleanup_close_ int fifo_fd = -1;
if (r < 0)
return r;
+ if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
+
do {
id = mfree(id);
SD_BUS_WRITABLE_PROPERTY("EnableWallMessages", "b", NULL, NULL, offsetof(Manager, enable_wall_messages), 0),
SD_BUS_WRITABLE_PROPERTY("WallMessage", "s", NULL, NULL, offsetof(Manager, wall_message), 0),
-// SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
+#if 0 /// UNNEEDED by elogind
+ SD_BUS_PROPERTY("NAutoVTs", "u", NULL, offsetof(Manager, n_autovts), SD_BUS_VTABLE_PROPERTY_CONST),
+#endif // 0
SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleSuspendKey", "s", property_get_handle_action, offsetof(Manager, handle_suspend_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleHibernateKey", "s", property_get_handle_action, offsetof(Manager, handle_hibernate_key), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitch", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("HandleLidSwitchExternalPower", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_ep), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HandleLidSwitchDocked", "s", property_get_handle_action, offsetof(Manager, handle_lid_switch_docked), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HoldoffTimeoutUSec", "t", NULL, offsetof(Manager, holdoff_timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IdleAction", "s", property_get_handle_action, offsetof(Manager, idle_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
+ SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectorySize", "t", NULL, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_hashmap_size, offsetof(Manager, inhibitors), 0),
+ SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_hashmap_size, offsetof(Manager, sessions), 0),
+ SD_BUS_PROPERTY("UserTasksMax", "t", property_get_compat_user_tasks_max, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SuspendThenHibernate", "b", NULL, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CanSuspendThenHibernate", NULL, "s", method_can_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
if (streq(result, "done"))
r = session_send_create_reply(s, NULL);
else {
- _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
r = session_send_create_reply(s, &e);
log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
/* Tell people that they now may take a lock again */
- send_prepare_for(m, m->action_what, false);
+ (void) send_prepare_for(m, m->action_what, false);
m->action_job = mfree(m->action_job);
m->action_unit = NULL;
}
#if 0 /// UNNEEDED by elogind
-int manager_start_slice(
- Manager *manager,
- const char *slice,
- const char *description,
- const char *after,
- const char *after2,
- uint64_t tasks_max,
- sd_bus_error *error,
- char **job) {
-
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+static int strdup_job(sd_bus_message *reply, char **job) {
+ const char *j;
+ char *copy;
int r;
- assert(manager);
- assert(slice);
-
- r = sd_bus_message_new_method_call(
- manager->bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "ss", strempty(slice), "fail");
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(m, 'a', "(sv)");
- if (r < 0)
- return r;
-
- if (!isempty(description)) {
- r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
- if (r < 0)
- return r;
- }
-
- if (!isempty(after)) {
- r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after);
- if (r < 0)
- return r;
- }
-
- if (!isempty(after2)) {
- r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ r = sd_bus_message_read(reply, "o", &j);
if (r < 0)
return r;
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "a(sa(sv))", 0);
- if (r < 0)
- return r;
-
- r = sd_bus_call(manager->bus, m, 0, error, &reply);
- if (r < 0)
- return r;
-
- if (job) {
- const char *j;
- char *copy;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- }
+ copy = strdup(j);
+ if (!copy)
+ return -ENOMEM;
+ *job = copy;
return 1;
}
const char *description,
const char *after,
const char *after2,
- uint64_t tasks_max,
+ sd_bus_message *more_properties,
sd_bus_error *error,
char **job) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
int r;
assert(manager);
assert(scope);
assert(pid > 1);
+ assert(job);
r = sd_bus_message_new_method_call(
manager->bus,
return r;
}
- /* cgroup empty notification is not available in containers
- * currently. To make this less problematic, let's shorten the
- * stop timeout for sessions, so that we don't wait
- * forever. */
-
- /* Make sure that the session shells are terminated with
- * SIGHUP since bash and friends tend to ignore SIGTERM */
+ /* Make sure that the session shells are terminated with SIGHUP since bash and friends tend to ignore
+ * SIGTERM */
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
if (r < 0)
return r;
if (r < 0)
return r;
- r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max);
+ /* disable TasksMax= for the session scope, rely on the slice setting for it */
+ r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", (uint64_t)-1);
if (r < 0)
- return r;
+ return bus_log_create_error(r);
+
+ if (more_properties) {
+ /* If TasksMax also appears here, it will overwrite the default value set above */
+ r = sd_bus_message_copy(m, more_properties, true);
+ if (r < 0)
+ return r;
+ }
r = sd_bus_message_close_container(m);
if (r < 0)
if (r < 0)
return r;
- if (job) {
- const char *j;
- char *copy;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- }
-
- return 1;
+ return strdup_job(reply, job);
}
int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
assert(manager);
assert(unit);
+ assert(job);
r = sd_bus_call_method(
manager->bus,
if (r < 0)
return r;
- if (job) {
- const char *j;
- char *copy;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- }
-
- return 1;
+ return strdup_job(reply, job);
}
int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
assert(manager);
assert(unit);
+ assert(job);
r = sd_bus_call_method(
manager->bus,
if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
- if (job)
- *job = NULL;
-
+ *job = NULL;
sd_bus_error_free(error);
return 0;
}
return r;
}
- if (job) {
- const char *j;
- char *copy;
-
- r = sd_bus_message_read(reply, "o", &j);
- if (r < 0)
- return r;
-
- copy = strdup(j);
- if (!copy)
- return -ENOMEM;
-
- *job = copy;
- }
-
- return 1;
+ return strdup_job(reply, job);
}
int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) {
}
int manager_unit_is_active(Manager *manager, const char *unit) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
const char *state;
int r;
}
int manager_job_is_active(Manager *manager, const char *path) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
int r;
assert(manager);
return true;
}
-#endif //
+#endif // 0