X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flogin%2Flogind-dbus.c;h=26a4ed889817b69a971d5202bccdc88ece7069a0;hb=d9537fde9944a03f48054e0f4b6a9aea7d3c2a9d;hp=e80b778cf711a5a3fae1c29625c142502f4da3a1;hpb=9fc8db12dbccc9e71f2c0761030eb5dbb9c1ff7a;p=elogind.git diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index e80b778cf..26a4ed889 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1,20 +1,8 @@ +/* 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 . ***/ #include @@ -28,6 +16,7 @@ #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" @@ -40,6 +29,7 @@ #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" @@ -52,29 +42,48 @@ /// Additional includes needed by elogind #include "elogind-dbus.h" -//#include "update-utmp.h" -int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { +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 == -ENXIO) - return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, - "Caller does not belong to any known session"); - if (r < 0) - return r; - } + if (isempty(name)) + return get_sender_session(m, message, error, ret); session = hashmap_get(m->sessions, name); if (!session) @@ -84,30 +93,48 @@ int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const ch 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_is_valid(uid)) { - _cleanup_(sd_bus_creds_unrefp) 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; @@ -218,9 +245,9 @@ static int property_get_preparing( 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); } @@ -253,60 +280,9 @@ static int property_get_scheduled_shutdown( } 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 int property_get_current_sessions( - 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, "t", (uint64_t) hashmap_size(m->sessions)); -} - -static int property_get_current_inhibitors( - 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, "t", (uint64_t) hashmap_size(m->inhibitors)); -} +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; @@ -333,6 +309,9 @@ static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_er 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; @@ -348,7 +327,7 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd r = sd_bus_message_read(message, "u", &pid); if (r < 0) return r; - if (!pid_is_valid((pid_t) pid)) + if (pid < 0) return -EINVAL; if (pid == 0) { @@ -411,7 +390,7 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu r = sd_bus_message_read(message, "u", &pid); if (r < 0) return r; - if (!pid_is_valid((pid_t) pid)) + if (pid < 0) return -EINVAL; if (pid == 0) { @@ -423,7 +402,9 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu 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); @@ -617,9 +598,9 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu 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; @@ -643,7 +624,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus 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)) @@ -689,7 +670,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus 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"); @@ -707,7 +688,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus 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) @@ -715,10 +696,6 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus } } - 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; @@ -747,9 +724,13 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus 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 @@ -783,9 +764,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus * 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); + log_warning("Existing logind session ID %s used by new audit session, ignoring.", id); audit_id = AUDIT_SESSION_INVALID; - id = mfree(id); } } @@ -871,15 +851,22 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus 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); #if 0 /// UNNEEDED by elogind - /* Now, let's wait until the slice unit and stuff got - * created. We send the reply back from + /* 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. */ @@ -1132,13 +1119,13 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus } 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 r, b, interactive; struct passwd *pw; const char *path; - uint32_t uid; - bool self = false; + uint32_t uid, auth_uid; assert(message); assert(m); @@ -1147,22 +1134,23 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - if (!uid_is_valid(uid)) { - _cleanup_(sd_bus_creds_unrefp) 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; + } - self = true; - - } 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); @@ -1172,7 +1160,8 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, - self ? "org.freedesktop.login1.set-self-linger" : "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, @@ -1183,9 +1172,9 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu 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; @@ -1193,7 +1182,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu if (!cc) return -ENOMEM; - path = strjoina("/var/lib/systemd/linger/", cc); + path = strjoina("/var/lib/elogind/linger/", cc); if (b) { User *u; @@ -1220,7 +1209,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu } 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; @@ -1251,14 +1240,14 @@ static int trigger_device(Manager *m, struct udev_device *d) { 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; @@ -1425,12 +1414,12 @@ static int bus_manager_log_shutdown( 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"; @@ -1447,8 +1436,7 @@ static int bus_manager_log_shutdown( return log_struct(LOG_NOTICE, "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR, p, - q, - NULL); + q); } #endif // 0 @@ -1497,8 +1485,11 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until) { return r; } -#if 0 /// elogind has its own variant in elogind-dbus.c +#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 static const char * const signal_name[_INHIBIT_WHAT_MAX] = { [INHIBIT_SHUTDOWN] = "PrepareForShutdown", @@ -1520,6 +1511,7 @@ static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { active); } +#if 0 /// elogind has its own variant in elogind-dbus.c static int execute_shutdown_or_sleep( Manager *m, InhibitWhat w, @@ -1573,10 +1565,11 @@ static int execute_shutdown_or_sleep( error: /* Tell people that they now may take a lock again */ - send_prepare_for(m, m->action_what, false); + (void) send_prepare_for(m, w, false); return r; } +#endif // 0 int manager_dispatch_delayed(Manager *manager, bool timeout) { @@ -1586,7 +1579,11 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) { 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)) { @@ -1604,25 +1601,31 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) { } /* 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("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; + /* It is not a critical error for elogind if suspending fails */ +#endif // 0 } return 1; } -#endif // 0 -#if 0 /// elogind-dbus.c needs to access this static int manager_inhibit_timeout_handler( -#else -int manager_inhibit_timeout_handler( -#endif // 0 sd_event_source *s, uint64_t usec, void *userdata) { @@ -1637,19 +1640,27 @@ int manager_inhibit_timeout_handler( return (r < 0) ? r : 0; } -#if 0 /// elogind has its own variant in elogind-dbus.c +#if 0 /// elogind does not have unit_name but action static int delay_shutdown_or_sleep( Manager *m, InhibitWhat w, 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; @@ -1668,42 +1679,59 @@ static int delay_shutdown_or_sleep( 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; } -#endif // 0 -#if 0 /// elogind-dbus.c needs to access this -#else -int send_prepare_for(Manager *m, InhibitWhat w, bool _active) { -#endif // 0 -#if 0 /// elogind has its own variant in elogind-dbus.c int bus_manager_shutdown_or_sleep_now_or_later( Manager *m, +#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); +#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(action), + handle_action_to_string(unit_name), delayed ? "" : "NOT "); if (delayed) /* Shutdown is delayed, keep in mind what we @@ -1716,13 +1744,8 @@ int bus_manager_shutdown_or_sleep_now_or_later( return r; } -#endif // 0 -#if 0 /// elogind-dbus.c needs to access this static int verify_shutdown_creds( -#else -int verify_shutdown_creds( -#endif // 0 Manager *m, sd_bus_message *message, InhibitWhat w, @@ -1784,11 +1807,14 @@ int verify_shutdown_creds( return 0; } -#if 0 /// elogind has its own variant in elogind-dbus.c static int method_do_shutdown_or_sleep( Manager *m, sd_bus_message *message, +#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, @@ -1800,7 +1826,9 @@ static int method_do_shutdown_or_sleep( 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); @@ -1816,19 +1844,35 @@ static int method_do_shutdown_or_sleep( 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); - log_debug_elogind("verify_shutdown_creds() returned %d", r); 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, unit_name, w, error); if (r < 0) @@ -1843,7 +1887,11 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error 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", @@ -1858,7 +1906,11 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * 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", @@ -1867,13 +1919,36 @@ static int method_reboot(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, +#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", @@ -1881,7 +1956,58 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error "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); +} static int nologin_timeout_handler( sd_event_source *s, @@ -1889,15 +2015,11 @@ static int nologin_timeout_handler( void *userdata) { Manager *m = userdata; - int r; log_info("Creating /run/nologin, blocking further logins..."); - r = write_string_file_atomic_label("/run/nologin", "System is going down."); - 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; } @@ -1909,7 +2031,7 @@ static int update_schedule_file(Manager *m) { 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"); @@ -1957,22 +2079,30 @@ fail: return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m"); } -#if 0 /// elogind has its own variant in elogind-dbus.c +#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("/run/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, @@ -1988,12 +2118,14 @@ static int manager_scheduled_shutdown_handler( if (isempty(m->scheduled_shutdown_type)) return 0; - if (streq(m->scheduled_shutdown_type, "halt")) - target = SPECIAL_HALT_TARGET; - else if (streq(m->scheduled_shutdown_type, "poweroff")) + if (streq(m->scheduled_shutdown_type, "poweroff")) target = SPECIAL_POWEROFF_TARGET; - else + 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 + assert_not_reached("unexpected shutdown type"); /* Don't allow multiple jobs being executed at the same time */ if (m->action_what) { @@ -2038,6 +2170,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ uint64_t elapse; char *type; int r; + bool dry_run = false; assert(m); assert(message); @@ -2049,10 +2182,14 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ 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"; @@ -2060,10 +2197,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ 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.power-off"; - action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit"; } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); @@ -2093,6 +2226,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ 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) @@ -2149,7 +2284,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd cancelled = m->scheduled_shutdown_type != NULL; reset_scheduled_shutdown(m); - if (cancelled) { + if (cancelled && m->enable_wall_messages) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *tty = NULL; uid_t uid = 0; @@ -2180,38 +2315,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd return sd_bus_reply_method_return(message, "b", cancelled); } -#if 0 /// elogind has its own variant in elogind-dbus.c -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, - SPECIAL_HIBERNATE_TARGET, - 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, - 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); -} -#endif // 0 - static int method_can_shutdown_or_sleep( Manager *m, sd_bus_message *message, @@ -2223,6 +2326,7 @@ static int method_can_shutdown_or_sleep( sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + HandleAction handle; bool multiple_sessions, challenge, blocked; const char *result = NULL; uid_t uid; @@ -2239,13 +2343,13 @@ static int method_can_shutdown_or_sleep( 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); @@ -2263,6 +2367,25 @@ static int method_can_shutdown_or_sleep( 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) @@ -2305,6 +2428,7 @@ static int method_can_shutdown_or_sleep( result = "no"; } + finish: return sd_bus_reply_method_return(message, "s", result); } @@ -2334,6 +2458,19 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err 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; @@ -2373,6 +2510,19 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b 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, @@ -2390,7 +2540,7 @@ static int property_get_reboot_to_firmware_setup( 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 @@ -2450,10 +2600,12 @@ static int method_can_reboot_to_firmware_setup( 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, @@ -2486,7 +2638,7 @@ static int method_set_wall_message( int r; Manager *m = userdata; char *wall_message; - int enable_wall_messages; + unsigned enable_wall_messages; assert(message); assert(m); @@ -2657,6 +2809,7 @@ const sd_bus_vtable manager_vtable[] = { 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), @@ -2666,12 +2819,12 @@ const sd_bus_vtable manager_vtable[] = { 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", bus_property_get_size, offsetof(Manager, runtime_dir_size), 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_current_inhibitors, 0, 0), + 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_current_sessions, 0, 0), - SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_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), @@ -2700,14 +2853,18 @@ const sd_bus_vtable manager_vtable[] = { 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), @@ -2770,7 +2927,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err 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; @@ -2930,78 +3087,6 @@ static int strdup_job(sd_bus_message *reply, char **job) { return 1; } -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_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; - int r; - - assert(manager); - assert(slice); - assert(job); - - 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); - 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; - - return strdup_job(reply, job); -} - int manager_start_scope( Manager *manager, const char *scope, @@ -3010,7 +3095,7 @@ int manager_start_scope( const char *description, const char *after, const char *after2, - uint64_t tasks_max, + sd_bus_message *more_properties, sd_bus_error *error, char **job) { @@ -3064,13 +3149,8 @@ int manager_start_scope( 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; @@ -3079,9 +3159,17 @@ int manager_start_scope( 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)