diff options
-rw-r--r-- | .packit.yml | 14 | ||||
-rw-r--r-- | docs/PORTABILITY_AND_STABILITY.md | 2 | ||||
-rw-r--r-- | man/org.freedesktop.login1.xml | 36 | ||||
-rw-r--r-- | man/systemctl.xml | 4 | ||||
-rw-r--r-- | man/systemd.preset.xml | 75 | ||||
-rw-r--r-- | meson.build | 12 | ||||
-rw-r--r-- | meson_options.txt | 2 | ||||
-rw-r--r-- | src/basic/login-util.h | 8 | ||||
-rw-r--r-- | src/basic/path-util.c | 25 | ||||
-rw-r--r-- | src/kernel-install/meson.build | 3 | ||||
-rw-r--r-- | src/libudev/libudev-list.c | 19 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 97 | ||||
-rw-r--r-- | src/systemctl/systemctl-logind.c | 17 | ||||
-rw-r--r-- | src/test/test-path-util.c | 6 | ||||
-rwxr-xr-x | tools/oss-fuzz.sh | 6 | ||||
-rwxr-xr-x | tools/update-dbus-docs.py | 2 |
16 files changed, 243 insertions, 85 deletions
diff --git a/.packit.yml b/.packit.yml index 0c3c17b9da..e1ace861dd 100644 --- a/.packit.yml +++ b/.packit.yml @@ -22,8 +22,18 @@ actions: # - Patch0000-0499: backported patches from upstream # - Patch0500-9999: downstream-only patches - "sed -ri '/^Patch0[0-4][0-9]{2}+\\:.+\\.patch/d' .packit_rpm/systemd.spec" - # Build the RPMs with -Werror to catch possible compiler warnings - - "sed -i 's/^%meson /%meson --werror /' .packit_rpm/systemd.spec" + # Build the RPMs with -Werror to catch possible compiler warnings. Since + # --werror in meson doesn't seem to work with -Db_lto=true [0], let's use + # -Dc_args= and -Dcpp_args= instead. + # + # Exceptions: + # - use -Wno-deprecated-declarations to get around mallinfo() use in + # basic/selinux-util.c + # - don't use -Werror on x86 architectures, otherwise all function checks + # will fail (with error: cast from pointer to integer of different size) + # + # [0] https://github.com/mesonbuild/meson/issues/7360 + - 'sed -i "/^CONFIGURE_OPTS=(/a%ifnarch i386 i686\n-Dc_args=\"-Werror -Wno-deprecated-declarations\" -Dcpp_args=\"-Werror -Wno-deprecated-declarations\"\n%endif" .packit_rpm/systemd.spec' jobs: - job: copr_build diff --git a/docs/PORTABILITY_AND_STABILITY.md b/docs/PORTABILITY_AND_STABILITY.md index 0caa5cc048..27562c17d8 100644 --- a/docs/PORTABILITY_AND_STABILITY.md +++ b/docs/PORTABILITY_AND_STABILITY.md @@ -120,7 +120,7 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy | `/run` | File hierarchy change | yes | yes | numerous | yes | OpenSUSE, Debian, ArchLinux | no | | [Generators](https://www.freedesktop.org/software/systemd/man/systemd.generator.html) | Subprocess | yes | yes | - | no | - | no | | [System Updates](https://www.freedesktop.org/software/systemd/man/systemd.offline-updates.html) | System Mode | yes | yes | - | no | - | no | -| [Presets](https://freedesktop.org/wiki/Software/systemd/Preset) | File format | yes | yes | - | no | - | no | +| [Presets](https://www.freedesktop.org/software/systemd/man/systemd.preset.html) | File format | yes | yes | - | no | - | no | | Udev rules | File format | yes | yes | numerous | no | no | partially | diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index ad27b226b8..bf7a5fa340 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -102,12 +102,19 @@ node /org/freedesktop/login1 { in b interactive); FlushDevices(in b interactive); PowerOff(in b interactive); + PowerOffWithFlags(in t flags); Reboot(in b interactive); + RebootWithFlags(in t flags); Halt(in b interactive); + HaltWithFlags(in t flags); Suspend(in b interactive); + SuspendWithFlags(in t flags); Hibernate(in b interactive); + HibernateWithFlags(in t flags); HybridSleep(in b interactive); + HybridSleepWithFlags(in t flags); SuspendThenHibernate(in b interactive); + SuspendThenHibernateWithFlags(in t flags); CanPowerOff(out s result); CanReboot(out s result); CanHalt(out s result); @@ -291,18 +298,32 @@ node /org/freedesktop/login1 { <variablelist class="dbus-method" generated="True" extra-ref="PowerOff()"/> + <variablelist class="dbus-method" generated="True" extra-ref="PowerOffWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Reboot()"/> + <variablelist class="dbus-method" generated="True" extra-ref="RebootWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Halt()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HaltWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Suspend()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="Hibernate()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HibernateWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HybridSleep()"/> + <variablelist class="dbus-method" generated="True" extra-ref="HybridSleepWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendThenHibernate()"/> + <variablelist class="dbus-method" generated="True" extra-ref="SuspendThenHibernateWithFlags()"/> + <variablelist class="dbus-method" generated="True" extra-ref="CanPowerOff()"/> <variablelist class="dbus-method" generated="True" extra-ref="CanReboot()"/> @@ -525,8 +546,19 @@ node /org/freedesktop/login1 { using an RTC timer and hibernated. The only argument is the polkit interactivity boolean <varname>interactive</varname> (see below). The main purpose of these calls is that they enforce polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged - users. They also enforce inhibition locks. UIs should expose these calls as the primary mechanism to - poweroff/reboot/suspend/hibernate the machine.</para> + users. They also enforce inhibition locks for non-privileged users. UIs should expose these calls + as the primary mechanism to poweroff/reboot/suspend/hibernate the machine. Methods + <function>PowerOffWithFlags()</function>, <function>RebootWithFlags()</function>, + <function>HaltWithFlags()</function>, <function>SuspendWithFlags()</function>, + <function>HibernateWithFlags()</function>, <function>HybridSleepWithFlags()</function> and + <function>SuspendThenHibernateWithFlags()</function> add <varname>flags</varname> to allow for + extendability, defined as follows:</para> + <programlisting> +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + </programlisting> + <para> When the <varname>flags</varname> is 0 then these methods behave just like the versions + without flags. When <constant>SD_LOGIND_ROOT_CHECK_INHIBITORS</constant> (0x01) is set, active + inhibitors are honoured for privileged users too.</para> <para><function>SetRebootParameter()</function> sets a parameter for a subsequent reboot operation. See the description of <command>reboot</command> in diff --git a/man/systemctl.xml b/man/systemctl.xml index e49a12a146..db4e2b2c65 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -793,9 +793,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err <para>For more information on the preset policy format, see <citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>. - For more information on the concept of presets, please consult the - <ulink url="https://www.freedesktop.org/wiki/Software/systemd/Preset">Preset</ulink> - document.</para> + </para> </listitem> </varlistentry> diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml index 5697e50be7..cbd89daf16 100644 --- a/man/systemd.preset.xml +++ b/man/systemd.preset.xml @@ -32,28 +32,20 @@ <refsect1> <title>Description</title> - <para>Preset files may be used to encode policy which units shall - be enabled by default and which ones shall be disabled. They are - read by <command>systemctl preset</command> (for more information - see - <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>) - which uses this information to enable or disable a unit according - to preset policy. <command>systemctl preset</command> is used by - the post install scriptlets of RPM packages (or other OS package - formats), to enable/disable specific units by default on package - installation, enforcing distribution, spin or administrator preset - policy. This allows choosing a certain set of units to be - enabled/disabled even before installing the actual package.</para> - - <para>For more information on the preset logic please have a look - at the <ulink - url="https://www.freedesktop.org/wiki/Software/systemd/Preset">Presets</ulink> - document.</para> - - <para>It is not recommended to ship preset files within the - respective software packages implementing the units, but rather - centralize them in a distribution or spin default policy, which - can be amended by administrator policy.</para> + <para>Preset files may be used to encode policy which units shall be enabled by default and which ones + shall be disabled. They are read by <command>systemctl preset</command> which uses this information to + enable or disable a unit. Depending on that policy, <command>systemctl preset</command> is identical to + <command>systemctl enable</command> or <command>systemctl disable</command>. + + <command>systemctl preset</command> is used by the post install scriptlets of rpm packages (or other OS + package formats), to enable/disable specific units by default on package installation, enforcing + distribution, spin or administrator preset policy. This allows choosing a certain set of units to be + enabled/disabled even before installing the actual package. For more information, see + <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> + + <para>It is not recommended to ship preset files within the respective software packages implementing the + units, but rather centralize them in a distribution or spin default policy, which can be amended by + administrator policy, see below.</para> <para>If no preset files exist, <command>systemctl preset</command> will enable all units that are installed by @@ -176,12 +168,51 @@ disable *</programlisting> </refsect1> <refsect1> + <title>Motiviation for the preset logic</title> + + <para>Different distributions have different policies on which services shall be enabled by default when + the package they are shipped in is installed. On Fedora all services stay off by default, so that + installing a package will not cause a service to be enabled (with some exceptions). On Debian all + services are immediately enabled by default, so that installing a package will cause its services to be + enabled right-away.</para> + + <para>Even within a single distribution, different spins (flavours, remixes, whatever you might want to + call them) of a distribution also have different policies on what services to enable, and what services + to leave off. For example, Fedora Workstation will enable <command>gdm</command> as display manager by + default, while the Fedora KDE spin will enable <command>sddm</command> instead.</para> + + <para>Different sites might also have different policies what to turn on by default and what to turn + off. For example, one administrator would prefer to enforce the policy of "<command>sshd</command> should + be always on, but everything else off", while another one might say "<command>snmpd</command> always on, + and for everything else use the distribution policy defaults".</para> + + <para>Traditionally, policy about which services shall be enabled were implemented in each package + individually. This made it cumbersome to implement different policies per spin or per site, or to create + software packages that do the right thing on more than one distribution. The enablement mechanism was + also encoding the enablement policy.</para> + + <para>The preset mechanism allows clean separation of the enablement mechanism (inside the package + scriptlets, by invoking <command>systemctl preset</command>) and enablement policy (centralized in the + preset files), and lifts the configuration out of individual packages. Preset files may be written for + specific distributions, for specific spins or for specific sites, in order to enforce different policies + as needed. It is recommended to apply the policy encoded in preset files in package installation + scriptlets.</para> + </refsect1> + + <refsect1> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-delta</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> + + <para><citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>8</manvolnum></citerefentry> + has a discussion of packaging scriptlets.</para> + + <para>Fedora page introducing the use of presets: + <ulink url="https://fedoraproject.org/wiki/Features/PackagePresets">Features/PackagePresets</ulink>. + </para> </refsect1> </refentry> diff --git a/meson.build b/meson.build index 0af0cce8b8..01eeeb750e 100644 --- a/meson.build +++ b/meson.build @@ -1450,14 +1450,6 @@ have = have and conf.get('HAVE_PAM') == 1 conf.set10('ENABLE_PAM_HOME', have) have = get_option('oomd') -if have == 'auto' - have = get_option('mode') == 'developer' -else - have = have == 'true' - if have and get_option('mode') != 'developer' - warning('oomd is not ready for release mode (yet)') - endif -endif conf.set10('ENABLE_OOMD', have) substs.set10('ENABLE_OOMD', have) @@ -3668,8 +3660,8 @@ status = [ conf.get('SYSTEM_ALLOC_UID_MIN')), 'system GIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'), conf.get('SYSTEM_ALLOC_GID_MIN')), - 'dynamic UIDs: @0@–@1@'.format(dynamic_uid_min, dynamic_uid_max), - 'container UID bases: @0@–@1@'.format(container_uid_base_min, container_uid_base_max), + 'dynamic UIDs: @0@…@1@'.format(dynamic_uid_min, dynamic_uid_max), + 'container UID bases: @0@…@1@'.format(container_uid_base_min, container_uid_base_max), '/dev/kvm access mode: @0@'.format(get_option('dev-kvm-mode')), 'render group access mode: @0@'.format(get_option('group-render-mode')), 'certificate root directory: @0@'.format(get_option('certificate-root')), diff --git a/meson_options.txt b/meson_options.txt index a421473029..425e958ba2 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -99,7 +99,7 @@ option('coredump', type : 'boolean', description : 'install the coredump handler') option('pstore', type : 'boolean', description : 'install the pstore archival tool') -option('oomd', type : 'combo', choices : ['auto', 'true', 'false'], +option('oomd', type : 'boolean', description : 'install the userspace oom killer') option('logind', type : 'boolean', description : 'install the systemd-logind stack') diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 00a124dc9f..dff87697a6 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -4,6 +4,14 @@ #include <stdbool.h> #include <unistd.h> +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + +/* For internal use only */ +#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63) + +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS) +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE) + bool session_id_valid(const char *id); static inline bool logind_running(void) { diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 5bcbc7a794..3dff09b151 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -823,6 +823,8 @@ const char *last_path_component(const char *path) { * Also, the empty string is mapped to itself. * * This is different than basename(), which returns "" when a trailing slash is present. + * + * This always succeeds (except if you pass NULL in which case it returns NULL, too). */ unsigned l, k; @@ -848,24 +850,24 @@ const char *last_path_component(const char *path) { int path_extract_filename(const char *p, char **ret) { _cleanup_free_ char *a = NULL; - const char *c, *e = NULL, *q; + const char *c; /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes - * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */ + * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. Returns + * -EADDRNOTAVAIL if specified parameter includes no filename (i.e. is "/" or so). Returns -EINVAL if + * not a valid path in the first place. */ - if (!p) + if (!path_is_valid(p)) return -EINVAL; - c = last_path_component(p); - - for (q = c; *q != 0; q++) - if (*q != '/') - e = q + 1; + /* Special case the root dir, because in that case we simply have no filename, but + * last_path_component() won't complain */ + if (path_equal(p, "/")) + return -EADDRNOTAVAIL; - if (!e) /* no valid character? */ - return -EINVAL; + c = last_path_component(p); - a = strndup(c, e - c); + a = strndup(c, strcspn(c, "/")); if (!a) return -ENOMEM; @@ -873,7 +875,6 @@ int path_extract_filename(const char *p, char **ret) { return -EINVAL; *ret = TAKE_PTR(a); - return 0; } diff --git a/src/kernel-install/meson.build b/src/kernel-install/meson.build index 4117188f14..92ce23ecf9 100644 --- a/src/kernel-install/meson.build +++ b/src/kernel-install/meson.build @@ -4,8 +4,7 @@ want_kernel_install = get_option('kernel-install') if want_kernel_install install_data('kernel-install', - install_mode : 'rwxr-xr-x', - install_dir : bindir) + install_mode : 'rwxr-xr-x') install_data('00-entry-directory.install', '50-depmod.install', diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c index 3b2a2cdee4..69efc1013c 100644 --- a/src/libudev/libudev-list.c +++ b/src/libudev/libudev-list.c @@ -39,9 +39,10 @@ static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entr return NULL; if (entry->list) { - if (entry->list->unique) + if (entry->list->unique && entry->name) hashmap_remove(entry->list->unique_entries, entry->name); - else + + if (!entry->list->unique || entry->list->uptodate) LIST_REMOVE(entries, entry->list->entries, entry); } @@ -70,9 +71,9 @@ struct udev_list *udev_list_new(bool unique) { struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) { _cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL; _cleanup_free_ char *name = NULL, *value = NULL; - int r; assert(list); + assert(_name); name = strdup(_name); if (!name) @@ -89,26 +90,22 @@ struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char * return NULL; *entry = (struct udev_list_entry) { - .list = list, .name = TAKE_PTR(name), .value = TAKE_PTR(value), }; if (list->unique) { - r = hashmap_ensure_allocated(&list->unique_entries, &string_hash_ops); - if (r < 0) - return NULL; - udev_list_entry_free(hashmap_get(list->unique_entries, entry->name)); - r = hashmap_put(list->unique_entries, entry->name, entry); - if (r < 0) + if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0) return NULL; list->uptodate = false; } else LIST_APPEND(entries, list->entries, entry); + entry->list = list; + return TAKE_PTR(entry); } @@ -119,8 +116,8 @@ void udev_list_cleanup(struct udev_list *list) { return; if (list->unique) { - hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); list->uptodate = false; + hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); } else LIST_FOREACH_SAFE(entries, i, n, list->entries) udev_list_entry_free(i); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index b95af1a9fd..8f27fe7ee9 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1793,14 +1793,14 @@ static int verify_shutdown_creds( Manager *m, sd_bus_message *message, InhibitWhat w, - bool interactive, const char *action, const char *action_multiple_sessions, const char *action_ignore_inhibit, + uint64_t flags, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - bool multiple_sessions, blocked; + bool multiple_sessions, blocked, interactive; uid_t uid; int r; @@ -1823,6 +1823,7 @@ static int verify_shutdown_creds( multiple_sessions = r > 0; blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + interactive = flags & SD_LOGIND_INTERACTIVE; if (multiple_sessions && action_multiple_sessions) { r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); @@ -1832,12 +1833,19 @@ static int verify_shutdown_creds( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ } - if (blocked && action_ignore_inhibit) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); - if (r < 0) - return r; - if (r == 0) - return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + if (blocked) { + /* We don't check polkit for root here, because you can't be more privileged than root */ + if (uid == 0 && (flags & SD_LOGIND_ROOT_CHECK_INHIBITORS)) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, + "Access denied to root due to active block inhibitor"); + + if (action_ignore_inhibit) { + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + } } if (!multiple_sessions && !blocked && action) { @@ -1860,9 +1868,11 @@ static int method_do_shutdown_or_sleep( const char *action_multiple_sessions, const char *action_ignore_inhibit, const char *sleep_verb, + bool with_flags, sd_bus_error *error) { - int interactive, r; + int interactive = false, r; + uint64_t flags = 0; assert(m); assert(message); @@ -1870,10 +1880,20 @@ static int method_do_shutdown_or_sleep( assert(w >= 0); assert(w <= _INHIBIT_WHAT_MAX); - r = sd_bus_message_read(message, "b", &interactive); + if (with_flags) + r = sd_bus_message_read(message, "t", &flags); + else + r = sd_bus_message_read(message, "b", &interactive); + if (r < 0) return r; + if (with_flags && (flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid flags parameter"); + + SET_FLAG(flags, SD_LOGIND_INTERACTIVE, interactive); + /* Don't allow multiple jobs being executed at the same time */ if (m->action_what > 0) return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, @@ -1891,8 +1911,8 @@ static int method_do_shutdown_or_sleep( return r; } - r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions, - action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions, + action_ignore_inhibit, flags, error); if (r != 0) return r; @@ -1914,6 +1934,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"), error); } @@ -1928,6 +1949,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * "org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"), error); } @@ -1942,6 +1964,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er "org.freedesktop.login1.halt-multiple-sessions", "org.freedesktop.login1.halt-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"), error); } @@ -1956,6 +1979,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-ignore-inhibit", "suspend", + sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"), error); } @@ -1970,6 +1994,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hibernate", + sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"), error); } @@ -1984,6 +2009,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"), error); } @@ -1998,6 +2024,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"), error); } @@ -2185,8 +2212,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); - r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false, - action, action_multiple_sessions, action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions, + action_ignore_inhibit, 0, error); if (r != 0) return r; @@ -3538,42 +3565,84 @@ static const sd_bus_vtable manager_vtable[] = { NULL,, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("PowerOffWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_poweroff, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Reboot", "b", SD_BUS_PARAM(interactive), NULL,, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("RebootWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_reboot, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Halt", "b", SD_BUS_PARAM(interactive), NULL,, method_halt, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HaltWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_halt, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Suspend", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Hibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("HybridSleep", "b", SD_BUS_PARAM(interactive), NULL,, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HybridSleepWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hybrid_sleep, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend_then_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("CanPowerOff", NULL,, "s", diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 4070c64257..103f81647d 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -6,6 +6,7 @@ #include "bus-error.h" #include "bus-locator.h" +#include "login-util.h" #include "process-util.h" #include "systemctl-logind.h" #include "systemctl-start-unit.h" @@ -57,6 +58,8 @@ int logind_reboot(enum action a) { }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method_with_flags; + uint64_t flags = 0; sd_bus *bus; int r; @@ -75,6 +78,20 @@ int logind_reboot(enum action a) { if (arg_dry_run) return 0; + SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0); + + method_with_flags = strjoina(actions[a].method, "WithFlags"); + + r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags); + if (r >= 0) + return 0; + if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) + return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); + + /* Fallback to original methods in case there is older version of systemd-logind */ + log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a].method); + sd_bus_error_free(&error); + r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password); if (r < 0) return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index fcaffa4539..206f5fd436 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -578,9 +578,9 @@ static void test_path_extract_filename(void) { test_path_extract_filename_one(NULL, NULL, -EINVAL); test_path_extract_filename_one("a/b/c", "c", 0); test_path_extract_filename_one("a/b/c/", "c", 0); - test_path_extract_filename_one("/", NULL, -EINVAL); - test_path_extract_filename_one("//", NULL, -EINVAL); - test_path_extract_filename_one("///", NULL, -EINVAL); + test_path_extract_filename_one("/", NULL, -EADDRNOTAVAIL); + test_path_extract_filename_one("//", NULL, -EADDRNOTAVAIL); + test_path_extract_filename_one("///", NULL, -EADDRNOTAVAIL); test_path_extract_filename_one(".", NULL, -EINVAL); test_path_extract_filename_one("./.", NULL, -EINVAL); test_path_extract_filename_one("././", NULL, -EINVAL); diff --git a/tools/oss-fuzz.sh b/tools/oss-fuzz.sh index 491246b32b..767da15f7c 100755 --- a/tools/oss-fuzz.sh +++ b/tools/oss-fuzz.sh @@ -38,7 +38,11 @@ else fi fi -meson $build -D$fuzzflag -Db_lundef=false +if ! meson $build -D$fuzzflag -Db_lundef=false; then + cat $build/meson-logs/meson-log.txt + exit 1 +fi + ninja -v -C $build fuzzers # The seed corpus is a separate flat archive for each fuzzer, diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index 269b2196a2..b453a0867e 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -197,7 +197,7 @@ def subst_output(document, programlisting, stats): print(f'COMMAND: {shlex_join(argv)}') try: - out = subprocess.check_output(argv, text=True) + out = subprocess.check_output(argv, universal_newlines=True) except FileNotFoundError: print(f'{executable} not found, ignoring', file=sys.stderr) return |