From: Adrian Szyndela Date: Mon, 17 Feb 2020 13:12:39 +0000 (+0100) Subject: Merge v236 into tizen X-Git-Tag: submit/tizen/20200402.112550^2~53 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=90932a624e2c56acc064a6a25fa18c30f2ca1678;p=platform%2Fupstream%2Fsystemd.git Merge v236 into tizen Change-Id: Id62f08b8ecf2a909a49e5f93b2f7594b3880ef44 --- 90932a624e2c56acc064a6a25fa18c30f2ca1678 diff --cc man/sd_bus_creds_get_pid.xml index 0407a96,6bc78ed..8306fd3 --- a/man/sd_bus_creds_get_pid.xml +++ b/man/sd_bus_creds_get_pid.xml @@@ -401,20 -405,17 +405,21 @@@ sd_bus_creds_get_owner_uid() will retrieve the numeric UID (user identifier) of the user who owns - the login session that the process is a part of. See + the user unit or login session that the process is a part of. See systemd-logind.service8. - For processes that are not part of a session, returns -ENXIO. + For processes that are not part of a user unit or session, returns + -ENXIO. - sd_bus_creds_has_effective_cap() will check whether the capability specified by - capability was set in the effective capabilities mask. A positive return value means that it - was set, zero means that it was not set, and a negative return value indicates an error. See capabilities7 and the - AmbientCapabilities= and CapabilityBoundingSet= settings in + sd_bus_creds_has_effective_cap() will + check whether the capability specified by + capability was set in the effective + capabilities mask. A positive return value means that is was + set, zero means that it was not set, and a negative return + value indicates an error. See + capabilities7 + and Capabilities= and + CapabilityBoundingSet= settings in systemd.exec5. diff --cc packaging/systemd.spec index b9c65cd,0000000..81d482c mode 100644,000000..100644 --- a/packaging/systemd.spec +++ b/packaging/systemd.spec @@@ -1,719 -1,0 +1,723 @@@ +# "enable foo" will turn into --enable-foo or --disable-foo +# depending "with_foo" macro +%define enable() %{expand:%%{?with_%{1}:--enable-%{1}}%%{!?with_%{1}:--disable-%{1}}} + +%define WITH_RANDOMSEED 0 +%define WITH_BASH_COMPLETION 0 +%define WITH_ZSH_COMPLETION 0 +%define WITH_COREDUMP 0 +%define WITH_BACKLIGHT 0 +%define WITH_TIMEDATED 0 +%define WITH_RFKILL 0 +%define WITH_MACHINED 0 +%define WITH_DOC 0 +%define WITH_HOSTNAMED 0 + +%define build_dir _build +%define dbuspolicydir %{_datadir}/dbus-1 + +# The 'meson' macro is defined in rpm macros, but it uses features from rpm 4.15 ({shrink, set_build_flags) +# Below is a version suitable for our purposes +%define meson \ + CFLAGS="${CFLAGS:-%optflags}" \ + export CFLAGS \ + %{__meson} \\\ + --buildtype=plain \\\ + --prefix=%{_prefix} \\\ + --libdir=%{_libdir} \\\ + --libexecdir=%{_libexecdir} \\\ + --bindir=%{_bindir} \\\ + --sbindir=%{_sbindir} \\\ + --includedir=%{_includedir} \\\ + --datadir=%{_datadir} \\\ + --mandir=%{_mandir} \\\ + --infodir=%{_infodir} \\\ + --localedir=%{_datadir}/locale \\\ + --sysconfdir=%{_sysconfdir} \\\ + --localstatedir=%{_localstatedir} \\\ + --sharedstatedir=%{_sharedstatedir} \\\ + --wrap-mode=%{__meson_wrap_mode} \\\ + %{_vpath_builddir} +# Ninja macros below are defined for ninja in e.g. fedora distro, but +# so far they are not provided by Tizen's ninja package. +%define __ninja %{_bindir}/ninja +%define __ninja_common_opts -v %{?_smp_flags} +%define ninja_build \ + %{__ninja} %{__ninja_common_opts} +%define ninja_install \ + DESTDIR=%{buildroot} %{__ninja} install %{__ninja_common_opts} + +Name: systemd - Version: 235 ++Version: 236 +Release: 0%{?release_flags} +# For a breakdown of the licensing, see README +License: LGPL-2.1+ and GPL-2.0+ +Summary: A System and Service Manager +Url: http://www.freedesktop.org/wiki/Software/systemd +Group: Base/Startup +Source0: https://github.com/systemd/systemd/archive/v%{version}.tar.gz +Source1: pamconsole-tmp.conf +Source2: %{name}-rpmlintrc +Source3: test-runner.c +Source4: wait-default-target.sh +Source5: wait-delayed-target.sh +Source6: org.tizen.system.conf +Source7: sysctl-tizen-override.conf +Source1001: systemd.manifest +BuildRequires: gperf +BuildRequires: intltool >= 0.40.0 +BuildRequires: libacl-devel +BuildRequires: libblkid-devel >= 2.20 +BuildRequires: libcap-devel +BuildRequires: libgcrypt-devel +BuildRequires: libkmod-devel >= 14 +%if %{?WITH_DOC} +BuildRequires: xsltproc +BuildRequires: docbook-xsl-stylesheets +%endif +BuildRequires: pam-devel +BuildRequires: pkgconfig +# BuildRequires: pkgconfig(dbus-1) # for remove circular dependency on OBS +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(liblzma) +BuildRequires: pkgconfig(libkmod) +BuildRequires: pkgconfig(mount) +BuildRequires: meson +BuildRequires: acl +BuildRequires: python +# Requires: dbus # for remove circular dependency on OBS +Requires: filesystem +Requires(post): coreutils +Requires(pre): coreutils +Requires(pre): /usr/bin/getent +Requires(pre): /usr/sbin/groupadd +Requires(post): %{_sbindir}/update-alternatives +Requires(preun): %{_sbindir}/update-alternatives + +Obsoletes: SysVinit < 2.86-24 +Obsoletes: sysvinit < 2.86-24 +Provides: SysVinit = 2.86-24 +Provides: sysvinit = 2.86-24 +Provides: /bin/systemctl +Provides: /sbin/shutdown +Provides: udev = %{version} +Obsoletes: udev < 183 + +%description +systemd is a system and service manager for Linux, compatible with +SysV and LSB init scripts. systemd provides aggressive parallelization +capabilities, uses socket and D-Bus activation for starting services, +offers on-demand starting of daemons, keeps track of processes using +Linux cgroups, supports snapshotting and restoring of the system +state, maintains mount and automount points and implements an +elaborate transactional dependency-based service control logic. It can +work as a drop-in replacement for sysvinit. + +%package -n libsystemd +License: LGPL-2.1+ +Summary: Systemd libraries +Group: Base/Startup +Obsoletes: libudev < 183 +Provides: libudev = %{version} +Obsoletes: systemd < 185-4 +Conflicts: systemd < 185-4 + +%description -n libsystemd +Libraries for systemd and udev, as well as the systemd PAM module. + +%package devel +License: LGPL-2.1+ +Summary: Development headers for systemd +Requires: %{name} = %{version} +Requires: libsystemd = %{version} +Provides: libudev-devel = %{version} +Obsoletes: libudev-devel < 183 + +%description devel +Development headers and auxiliary files for developing applications for systemd. + +%package analyze +License: LGPL-2.1+ +Summary: Tool for processing systemd profiling information +Requires: %{name} = %{version} +Obsoletes: systemd < 38-5 + +%description analyze +'systemd-analyze blame' lists which systemd unit needed how much time to finish +initialization at boot. +'systemd-analyze plot' renders an SVG visualizing the parallel start of units +at boot. + +%package tests +License: LGPL-2.1+ and BSD-2-Clause +Summary: Set of tests for sd-bus component +Requires: %{name} = %{version} + +%description tests +This package is part of 'dbus-integratnion-tests' framework and contains set of tests +for sd-bus component (DBUS API C library). + +%package extension-kdbus +Summary: Extension for systemd to support KDBUS in Tizen +Requires: %{name} = %{version}-%{release} + +%description extension-kdbus +This modifies systemd to support KDBUS in Tizen. + +%prep +%setup -q + +%build +cp %{SOURCE1001} . +cp %{SOURCE3} . + +%define _vpath_srcdir . +%define _vpath_builddir %{build_dir} +%meson \ + -Dkdbus=true \ +%if ! %{WITH_RANDOMSEED} + -Drandomseed=false \ +%endif +%if ! %{?WITH_COREDUMP} + -Dcoredump=false \ +%endif +%if ! %{?WITH_BACKLIGHT} + -Dbacklight=false \ +%endif +%if ! %{?WITH_TIMEDATED} + -Dtimedated=false \ +%endif +%if ! %{WITH_RFKILL} + -Drfkill=false \ +%endif + -Dhwdb=false \ + -Dsysusers=false \ + -Dfirstboot=false \ + -Dpolkit=false \ + -Dtimesyncd=false \ + -Dresolve=false \ + -Dnetworkd=false \ +%if ! %{?WITH_MACHINED} + -Dmachined=false \ +%endif +%if ! %{?WITH_HOSTNAMED} + -Dhostnamed=false \ +%endif + -Dimportd=false \ + -Denvironment-d=false \ + -Dnss-systemd=false \ + -Dgcrypt=false \ +%if ! %{?WITH_DOC} + -Dman=false \ +%endif + -Drpmmacrosdir=%{_sysconfdir}/rpm/ \ + -Dsysvinit-path="" \ + -Dsysvrcnd-path="" \ + -Dsmack-run-label=System::Privileged \ + -Dinstall-tests=true \ + -Ddefault-hierarchy=legacy \ + -Db_pie=true +%meson_build + +# compile test-runner for 'dbus-integration-test' framework +%__cc %{_builddir}/%{name}-%{version}/test-runner.c -o %{_builddir}/%{name}-%{version}/systemd-tests + +%install +%meson_install +%find_lang %{name} +cat <> systemd.lang +%lang(be) /usr/lib/systemd/catalog/systemd.be.catalog +%lang(be) /usr/lib/systemd/catalog/systemd.be@latin.catalog +%lang(bg) /usr/lib/systemd/catalog/systemd.bg.catalog +%lang(de) /usr/lib/systemd/catalog/systemd.de.catalog +%lang(fr) /usr/lib/systemd/catalog/systemd.fr.catalog +%lang(it) /usr/lib/systemd/catalog/systemd.it.catalog +%lang(pl) /usr/lib/systemd/catalog/systemd.pl.catalog +%lang(pt_BR) /usr/lib/systemd/catalog/systemd.pt_BR.catalog +%lang(ru) /usr/lib/systemd/catalog/systemd.ru.catalog +%lang(zh) /usr/lib/systemd/catalog/systemd.zh_CN.catalog +%lang(zh) /usr/lib/systemd/catalog/systemd.zh_TW.catalog +EOF + +# udev links +/usr/bin/mkdir -p %{buildroot}/%{_sbindir} +/usr/bin/ln -sf ../bin/udevadm %{buildroot}%{_sbindir}/udevadm +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/firmware/updates + +# Create SysV compatibility symlinks. systemctl/systemd are smart +# enough to detect in which way they are called. +/usr/bin/ln -s ../lib/systemd/systemd %{buildroot}%{_sbindir}/init +/usr/bin/ln -s ../lib/systemd/systemd %{buildroot}%{_bindir}/systemd +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/reboot +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/halt +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/poweroff +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/shutdown +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/telinit +/usr/bin/ln -s ../bin/systemctl %{buildroot}%{_sbindir}/runlevel + +# legacy links +/usr/bin/ln -s loginctl %{buildroot}%{_bindir}/systemd-loginctl + +# We create all wants links manually at installation time to make sure +# they are not owned and hence overriden by rpm after the used deleted +# them. +/usr/bin/rm -r %{buildroot}%{_sysconfdir}/systemd/system/*.target.wants + +# Make sure these directories are properly owned +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/basic.target.wants +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/default.target.wants +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/dbus.target.wants +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system/syslog.target.wants + +# Make sure the user generators dir exists too +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-generators +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/user-generators + +# Create new-style configuration files so that we can ghost-own them +/usr/bin/touch %{buildroot}%{_sysconfdir}/hostname +/usr/bin/touch %{buildroot}%{_sysconfdir}/vconsole.conf +/usr/bin/touch %{buildroot}%{_sysconfdir}/locale.conf +/usr/bin/touch %{buildroot}%{_sysconfdir}/machine-id +/usr/bin/touch %{buildroot}%{_sysconfdir}/machine-info +/usr/bin/touch %{buildroot}%{_sysconfdir}/timezone + +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-preset/ +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/user-preset/ + +# Make sure the shutdown/sleep drop-in dirs exist +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-shutdown/ +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/system-sleep/ + +# Make sure the NTP units dir exists +/usr/bin/mkdir -p %{buildroot}%{_prefix}/lib/systemd/ntp-units.d/ + +# Install modprobe fragment +/usr/bin/mkdir -p %{buildroot}%{_sysconfdir}/modprobe.d/ + +# Fix the dangling /var/lock -> /run/lock symlink +install -Dm644 tmpfiles.d/legacy.conf %{buildroot}%{_prefix}/lib/tmpfiles.d/legacy.conf + +install -m644 %{SOURCE1} %{buildroot}%{_prefix}/lib/tmpfiles.d/ + +install -m 755 -d %{buildroot}/%{_prefix}/lib/systemd/system + +rm -rf %{buildroot}/%{_docdir}/%{name} + +# Allow replacing systemd-shutdown with tizen-specific variant +mv %{buildroot}%{_prefix}/lib/systemd/systemd-shutdown %{buildroot}%{_prefix}/lib/systemd/systemd-shutdown-original + +# Disable some useless services in Tizen +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/sysinit.target.wants/dev-hugepages.mount +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/sysinit.target.wants/sys-fs-fuse-connections.mount +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/sysinit.target.wants/systemd-binfmt.service +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/sysinit.target.wants/systemd-modules-load.service +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/sysinit.target.wants/systemd-ask-password-console.path +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/multi-user.target.wants/systemd-ask-password-wall.path +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/systemd-tmpfiles-clean.timer +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/systemd-tmpfiles-clean.service +rm -rf %{buildroot}/%{_prefix}/lib/systemd/system/timers.target.wants/systemd-tmpfiles-clean.timer ++rm -rf %{buildroot}/%{_prefix}/lib/systemd/user/systemd-tmpfiles-clean.timer ++rm -rf %{buildroot}/%{_prefix}/lib/systemd/user/systemd-tmpfiles-clean.service ++rm -rf %{buildroot}/%{_prefix}/lib/systemd/user/systemd-tmpfiles-setup.service + +# Exclude ELF binaries +rm -f %{buildroot}/%{_prefix}/lib/systemd/system-generators/systemd-debug-generator +rm -f %{buildroot}/%{_prefix}/lib/systemd/system-generators/systemd-efi-boot-generator +rm -f %{buildroot}/%{_prefix}/lib/systemd/system-generators/systemd-gpt-auto-generator +rm -f %{buildroot}/%{_prefix}/lib/systemd/system-generators/systemd-hibernate-resume-generator + +# Marker file for kdbus +touch %{buildroot}/%{_sysconfdir}/systemd/extension-kdbus + +# Prepare tests for 'dbus-integration-test' framework +install -D -m 755 %{_builddir}/%{name}-%{version}/systemd-tests %{buildroot}%{_prefix}/lib/dbus-tests/runner/systemd-tests +mkdir -p %{buildroot}%{_prefix}/lib/dbus-tests/test-suites/systemd-tests/ +mv %{buildroot}%{_prefix}/lib/systemd/tests/test-bus-* %{buildroot}%{_prefix}/lib/dbus-tests/test-suites/systemd-tests/ + +# Shell Completion +%if ! %{?WITH_BASH_COMPLETION} +rm -rf %{buildroot}/%{_datadir}/bash-completion/* +%endif +%if ! %{?WITH_ZSH_COMPLETION} +rm -rf %{buildroot}/%{_datadir}/zsh/site-functions/* +%endif + +mkdir -p %{buildroot}/%{_localstatedir}/log/journal + +ln -sf ./libsystemd.pc %{buildroot}%{_libdir}/pkgconfig/libsystemd-daemon.pc +ln -sf ./libsystemd.pc %{buildroot}%{_libdir}/pkgconfig/libsystemd-id128.pc +ln -sf ./libsystemd.pc %{buildroot}%{_libdir}/pkgconfig/libsystemd-journal.pc +ln -sf ./libsystemd.pc %{buildroot}%{_libdir}/pkgconfig/libsystemd-login.pc + +# Delayed target +install -m 0755 %{SOURCE4} %{buildroot}%{_bindir}/wait-default-target.sh +install -m 0755 %{SOURCE5} %{buildroot}%{_bindir}/wait-delayed-target.sh +install -m 0755 %{SOURCE6} %{buildroot}%{dbuspolicydir}/system.d/org.tizen.system.conf + +# Tizen sysctl values overriding default systemd values +install -m 0644 %{SOURCE7} %{buildroot}%{_sysconfdir}/sysctl.d/ + +# end of install +%pre +/usr/bin/getent group cdrom >/dev/null 2>&1 || /usr/sbin/groupadd -r -g 11 cdrom >/dev/null 2>&1 || : +/usr/bin/getent group tape >/dev/null 2>&1 || /usr/sbin/groupadd -r -g 33 tape >/dev/null 2>&1 || : +/usr/bin/getent group dialout >/dev/null 2>&1 || /usr/sbin/groupadd -r -g 18 dialout >/dev/null 2>&1 || : +/usr/bin/getent group floppy >/dev/null 2>&1 || /usr/sbin/groupadd -r -g 19 floppy >/dev/null 2>&1 || : +/usr/bin/systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service >/dev/null 2>&1 || : + +# Rename configuration files that changed their names +/usr/bin/mv -n %{_sysconfdir}/systemd/systemd-logind.conf %{_sysconfdir}/systemd/logind.conf >/dev/null 2>&1 || : +/usr/bin/mv -n %{_sysconfdir}/systemd/systemd-journald.conf %{_sysconfdir}/systemd/journald.conf >/dev/null 2>&1 || : + +%post +/usr/bin/systemd-machine-id-setup > /dev/null 2>&1 || : +%if %{WITH_RANDOMSEED} +/usr/lib/systemd/systemd-random-seed save > /dev/null 2>&1 || : +%endif +/usr/bin/systemctl daemon-reexec > /dev/null 2>&1 || : +/usr/bin/systemctl start systemd-udevd.service >/dev/null 2>&1 || : +/usr/bin/mkdir -p /etc/systemd/network +/usr/bin/ln -sf /dev/null /etc/systemd/network/99-default.link + +# Set the smack label of executable binary tools +chsmack %{_bindir}/bootctl -a "System::Tools" +chsmack %{_bindir}/busctl -a "System::Tools" +chsmack %{_bindir}/kernel-install -a "System::Tools" +%if %{?WITH_MACHINED} +chsmack %{_bindir}/machinectl -a "System::Tools" +%endif +chsmack %{_bindir}/systemd-run -a "System::Tools" +%if %{?WITH_HOSTNAMED} +chsmack %{_bindir}/hostnamectl -a "System::Tools" +%endif +chsmack %{_bindir}/localectl -a "System::Tools" +%if %{?WITH_COREDUMP} +chsmack %{_bindir}/coredumpctl -a "System::Tools" +%endif +%if %{?WITH_TIMEDATED} +chsmack %{_bindir}/timedatectl -a "System::Tools" +%endif +chsmack %{_bindir}/systemd -a "System::Tools" +chsmack %{_bindir}/systemctl -a "System::Tools" +chsmack %{_bindir}/systemd-notify -a "System::Tools" +chsmack %{_bindir}/systemd-ask-password -a "System::Tools" +chsmack %{_bindir}/systemd-tty-ask-password-agent -a "System::Tools" +chsmack %{_bindir}/systemd-machine-id-setup -a "System::Tools" +chsmack %{_bindir}/systemd-socket-activate -a "System::Tools" +chsmack %{_bindir}/loginctl -a "System::Tools" +chsmack %{_bindir}/systemd-loginctl -a "System::Tools" +chsmack %{_bindir}/journalctl -a "System::Tools" +chsmack %{_bindir}/systemd-tmpfiles -a "System::Tools" +chsmack %{_bindir}/systemd-nspawn -a "System::Tools" +chsmack %{_bindir}/systemd-stdio-bridge -a "System::Tools" +chsmack %{_bindir}/systemd-cat -a "System::Tools" +chsmack %{_bindir}/systemd-cgls -a "System::Tools" +chsmack %{_bindir}/systemd-cgtop -a "System::Tools" +chsmack %{_bindir}/systemd-delta -a "System::Tools" +chsmack %{_bindir}/systemd-detect-virt -a "System::Tools" +chsmack %{_bindir}/systemd-inhibit -a "System::Tools" +chsmack %{_bindir}/udevadm -a "System::Tools" +chsmack %{_bindir}/systemd-escape -a "System::Tools" +chsmack %{_bindir}/systemd-path -a "System::Tools" +chsmack %{_prefix}/lib/systemd/* -a "System::Tools" + +%postun +if [ $1 -ge 1 ] ; then + /usr/bin/systemctl daemon-reload > /dev/null 2>&1 || : + /usr/bin/systemctl try-restart systemd-logind.service >/dev/null 2>&1 || : +fi + +%preun +if [ $1 -eq 0 ] ; then + /usr/bin/systemctl disable \ + getty@.service \ + remote-fs.target \ + systemd-readahead-replay.service \ + systemd-readahead-collect.service >/dev/null 2>&1 || : + + update-alternatives --remove systemd-shutdown %{_prefix}/lib/systemd/systemd-shutdown-original +fi + +%posttrans +# Update alternatives after the whole transaction is completed - this is +# necessary due to RPM ordering, which removes files from old package not +# provided by new package after regular post scripts are run. Please refer +# to following guideliness for explanation: +# https://fedoraproject.org/wiki/Packaging:Scriptlets#Ordering +if [ $1 -eq 0 ]; then + update-alternatives --install %{_prefix}/lib/systemd/systemd-shutdown systemd-shutdown %{_prefix}/lib/systemd/systemd-shutdown-original 100 || : +fi + +%post -n libsystemd -p /sbin/ldconfig +%postun -n libsystemd -p /sbin/ldconfig + +%lang_package + +%files +%manifest %{name}.manifest +%license LICENSE.LGPL2.1 LICENSE.GPL2 +%config %{_sysconfdir}/pam.d/systemd-user +%{_bindir}/bootctl +%{_bindir}/busctl +%{_bindir}/kernel-install +%if %{?WITH_MACHINED} +%{_bindir}/machinectl +%endif +%{_bindir}/systemd-run +%dir %{_prefix}/lib/kernel +%dir %{_prefix}/lib/kernel/install.d +%{_prefix}/lib/kernel/install.d/50-depmod.install +%{_prefix}/lib/kernel/install.d/90-loaderentry.install +%if %{?WITH_HOSTNAMED} +%{_bindir}/hostnamectl +%endif +%{_bindir}/localectl +%if %{?WITH_COREDUMP} +%{_bindir}/coredumpctl +%endif +%if %{?WITH_TIMEDATED} +%{_bindir}/timedatectl +%endif +%dir %{_sysconfdir}/systemd +%dir %{_sysconfdir}/systemd/system +%dir %{_sysconfdir}/systemd/user +%dir %{_sysconfdir}/tmpfiles.d +%dir %{_sysconfdir}/sysctl.d +%dir %{_sysconfdir}/modules-load.d +%dir %{_sysconfdir}/binfmt.d +%if %{?WITH_BASH_COMPLETION} +%{_datadir}/bash-completion/* +%endif +%if %{?WITH_ZSH_COMPLETION} +%dir %{_datadir}/zsh/site-functions +%{_datadir}/zsh/site-functions/* +%endif +%dir %{_sysconfdir}/udev +%dir %{_sysconfdir}/udev/rules.d +%dir %{_prefix}/lib/systemd +%dir %{_prefix}/lib/systemd/system +%dir %{_prefix}/lib/systemd/system-generators +%dir %{_prefix}/lib/systemd/user-generators +%dir %{_prefix}/lib/systemd/system-preset +%dir %{_prefix}/lib/systemd/user-preset +%dir %{_prefix}/lib/systemd/system-shutdown +%dir %{_prefix}/lib/systemd/system-sleep +%dir %{_prefix}/lib/tmpfiles.d +%dir %{_prefix}/lib/sysctl.d +%dir %{_prefix}/lib/modules-load.d +%dir %{_prefix}/lib/binfmt.d +%dir %{_prefix}/lib/firmware +%dir %{_prefix}/lib/firmware/updates +%dir %{_datadir}/systemd +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.systemd1.conf +%if %{?WITH_HOSTNAMED} +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.hostname1.conf +%endif +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.login1.conf +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.locale1.conf +%if %{?WITH_TIMEDATED} +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.timedate1.conf +%endif +%if %{?WITH_MACHINED} +%config(noreplace) %{dbuspolicydir}/system.d/org.freedesktop.machine1.conf +%endif +%if %{?WITH_COREDUMP} +%config(noreplace) %{_sysconfdir}/systemd/coredump.conf +%else +%exclude %{_sysconfdir}/systemd/coredump.conf +%endif +%config(noreplace) %{_sysconfdir}/systemd/system.conf +%config(noreplace) %{_sysconfdir}/systemd/user.conf +%config(noreplace) %{_sysconfdir}/systemd/logind.conf +%config(noreplace) %{_sysconfdir}/systemd/journald.conf +%config(noreplace) %{_sysconfdir}/udev/udev.conf +%config(noreplace) %{_sysconfdir}/sysctl.d/sysctl-tizen-override.conf +%{_sysconfdir}/xdg/systemd +%ghost %config(noreplace) %{_sysconfdir}/hostname +%ghost %config(noreplace) %{_sysconfdir}/vconsole.conf +%ghost %config(noreplace) %{_sysconfdir}/locale.conf +%ghost %config(noreplace) %{_sysconfdir}/machine-id +%ghost %config(noreplace) %{_sysconfdir}/machine-info +%ghost %config(noreplace) %{_sysconfdir}/timezone +%exclude %{_sysconfdir}/X11/xinit/xinitrc.d/50-systemd-user.sh +%{_bindir}/systemd +%{_bindir}/systemctl +%{_bindir}/systemd-notify +%{_bindir}/systemd-ask-password +%{_bindir}/systemd-tty-ask-password-agent +%{_bindir}/systemd-machine-id-setup +%{_bindir}/systemd-socket-activate +%{_bindir}/loginctl +%{_bindir}/systemd-loginctl +%{_bindir}/journalctl +%{_bindir}/systemd-tmpfiles +%{_bindir}/systemd-nspawn +%{_bindir}/systemd-stdio-bridge +%{_bindir}/systemd-cat +%{_bindir}/systemd-cgls +%{_bindir}/systemd-cgtop +%{_bindir}/systemd-delta +%{_bindir}/systemd-detect-virt +%{_bindir}/systemd-inhibit +%{_bindir}/udevadm +%{_bindir}/systemd-escape +%{_bindir}/systemd-path +%{_bindir}/systemd-mount +%{_bindir}/systemd-umount +%{_prefix}/lib/sysctl.d/*.conf +%{_prefix}/lib/systemd/systemd +%{_prefix}/lib/systemd/system + +%dir %{_prefix}/lib/systemd/system/basic.target.wants +%dir %{_prefix}/lib/systemd/user +%dir %{_prefix}/lib/systemd/network +%dir %{_prefix}/lib/systemd/user/default.target.wants +%{_prefix}/lib/systemd/user/basic.target +%{_prefix}/lib/systemd/user/exit.target +%{_prefix}/lib/systemd/user/printer.target +%{_prefix}/lib/systemd/user/shutdown.target +%{_prefix}/lib/systemd/user/sockets.target +%{_prefix}/lib/systemd/user/sound.target +%{_prefix}/lib/systemd/user/systemd-exit.service +%{_prefix}/lib/systemd/user/paths.target +%{_prefix}/lib/systemd/user/smartcard.target +%{_prefix}/lib/systemd/user/timers.target +%{_prefix}/lib/systemd/user/default.target +%exclude %{_prefix}/lib/systemd/user/graphical-session.target +%exclude %{_prefix}/lib/systemd/user/graphical-session-pre.target +%{_prefix}/lib/systemd/network/99-default.link +%exclude %{_prefix}/lib/systemd/system-preset/90-systemd.preset ++%exclude %{_prefix}/lib/systemd/user-preset/90-systemd.preset +%{_prefix}/lib/systemd/user/delayed.target +%{_prefix}/lib/systemd/user/user-delayed-target-trigger.service +%{_prefix}/lib/systemd/user/default.target.wants/user-delayed-target-trigger.service +%{_prefix}/lib/systemd/user/user-default-target-done.service +%{_prefix}/lib/systemd/user/default.target.wants/user-default-target-done.service +%{_prefix}/lib/systemd/user/user-delayed-target-done.service +%{_prefix}/lib/systemd/user/delayed.target.wants/user-delayed-target-done.service +%{dbuspolicydir}/system.d/org.tizen.system.conf +%exclude %{_prefix}/lib/modprobe.d/systemd.conf + +%{_prefix}/lib/systemd/libsystemd-shared-%{version}.so +%{_prefix}/lib/systemd/systemd-* +%dir %{_prefix}/lib/systemd/catalog +%{_prefix}/lib/systemd/catalog/systemd.catalog +%{_prefix}/lib/udev +%{_prefix}/lib/systemd/system-generators/systemd-getty-generator +%{_prefix}/lib/systemd/system-generators/systemd-fstab-generator +%{_prefix}/lib/systemd/system-generators/systemd-system-update-generator +%{_prefix}/lib/tmpfiles.d/home.conf +%{_prefix}/lib/tmpfiles.d/journal-nocow.conf +%{_prefix}/lib/tmpfiles.d/legacy.conf +%{_prefix}/lib/tmpfiles.d/pamconsole-tmp.conf +%{_prefix}/lib/tmpfiles.d/systemd.conf +%{_prefix}/lib/tmpfiles.d/systemd-nologin.conf +%{_prefix}/lib/tmpfiles.d/systemd-nspawn.conf +%{_prefix}/lib/tmpfiles.d/tmp.conf +%{_prefix}/lib/tmpfiles.d/var.conf +%{_prefix}/lib/tmpfiles.d/x11.conf +%{_sbindir}/init +%{_sbindir}/reboot +%{_sbindir}/halt +%{_sbindir}/poweroff +%{_sbindir}/shutdown +%{_sbindir}/telinit +%{_sbindir}/runlevel +%{_sbindir}/udevadm +%{_datadir}/systemd/graphinfo.gvpr +%{_datadir}/systemd/kbd-model-map +%{_datadir}/systemd/language-fallback-map +%{_datadir}/dbus-1/services/org.freedesktop.systemd1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.systemd1.service +%if %{?WITH_HOSTNAMED} +%{_datadir}/dbus-1/system-services/org.freedesktop.hostname1.service +%endif +%{_datadir}/dbus-1/system-services/org.freedesktop.login1.service +%{_datadir}/dbus-1/system-services/org.freedesktop.locale1.service +%if %{?WITH_TIMEDATED} +%{_datadir}/dbus-1/system-services/org.freedesktop.timedate1.service +%endif +%if %{?WITH_MACHINED} +%{_datadir}/dbus-1/system-services/org.freedesktop.machine1.service +%endif +%dir %{_datadir}/factory/ +%dir %{_datadir}/factory/etc +%dir %{_datadir}/factory/etc/pam.d +%{_datadir}/factory/etc/nsswitch.conf +%{_datadir}/factory/etc/pam.d/other +%{_datadir}/factory/etc/pam.d/system-auth + +%{_localstatedir}/log/journal + +%{_bindir}/wait-default-target.sh +%{_bindir}/wait-delayed-target.sh +%exclude %{_prefix}/lib/systemd/system/runlevel0.target +%exclude %{_prefix}/lib/systemd/system/runlevel1.target +%exclude %{_prefix}/lib/systemd/system/runlevel2.target +%exclude %{_prefix}/lib/systemd/system/runlevel3.target +%exclude %{_prefix}/lib/systemd/system/runlevel4.target +%exclude %{_prefix}/lib/systemd/system/runlevel5.target +%exclude %{_prefix}/lib/systemd/system/runlevel6.target + +%files -n libsystemd +%manifest %{name}.manifest +%license LICENSE.LGPL2.1 +%{_libdir}/security/pam_systemd.so +%{_libdir}/libsystemd.so.* +%{_libdir}/libudev.so.* +%{_libdir}/libnss_myhostname.so.2 +%if %{?WITH_MACHINED} +%{_libdir}/libnss_mymachines.so.2 +%endif + +%files extension-kdbus +%manifest %{name}.manifest +%license LICENSE.LGPL2.1 LICENSE.GPL2 +%{_sysconfdir}/systemd/extension-kdbus +%{_prefix}/lib/systemd/user/busnames.target +%{_prefix}/lib/systemd/system-generators/systemd-dbus1-generator +%{_prefix}/lib/systemd/user-generators/systemd-dbus1-generator + +%files devel +%manifest %{name}.manifest +%{_libdir}/libudev.so +%{_libdir}/libsystemd.so +%dir %{_includedir}/systemd +%{_includedir}/systemd/sd-bus.h +%{_includedir}/systemd/sd-bus-protocol.h +%{_includedir}/systemd/sd-bus-vtable.h +%{_includedir}/systemd/sd-event.h +%{_includedir}/systemd/_sd-common.h +%{_includedir}/systemd/sd-daemon.h +%{_includedir}/systemd/sd-id128.h +%{_includedir}/systemd/sd-journal.h +%{_includedir}/systemd/sd-login.h +%{_includedir}/systemd/sd-messages.h +%{_includedir}/libudev.h +%{_libdir}/pkgconfig/libudev.pc +%{_libdir}/pkgconfig/libsystemd.pc +%{_datadir}/pkgconfig/systemd.pc +%{_datadir}/pkgconfig/udev.pc +%{_libdir}/pkgconfig/libsystemd-daemon.pc +%{_libdir}/pkgconfig/libsystemd-id128.pc +%{_libdir}/pkgconfig/libsystemd-journal.pc +%{_libdir}/pkgconfig/libsystemd-login.pc +%{_sysconfdir}/rpm/macros.systemd + +%files analyze +%manifest %{name}.manifest +%license LICENSE.LGPL2.1 +%{_bindir}/systemd-analyze + +%files tests +%manifest %{name}.manifest +%{_prefix}/lib/dbus-tests/test-suites/systemd-tests/ +%{_prefix}/lib/dbus-tests/runner/systemd-tests +%{_prefix}/lib/systemd/tests/ + +%if %{?WITH_DOC} +%docs_package +%else +%exclude %{_docdir} +%exclude %{_datadir}/doc/systemd +%endif diff --cc rules/meson.build index 28c375d,e253b9f..c949911 --- a/rules/meson.build +++ b/rules/meson.build @@@ -1,5 -1,21 +1,22 @@@ + # SPDX-License-Identifier: LGPL-2.1+ + # + # Copyright 2017 Zbigniew Jędrzejewski-Szmek + # + # 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 . + rules = files(''' + 55-udev-smack-default.rules 60-block.rules 60-cdrom_id.rules 60-drm.rules diff --cc src/basic/fs-util.c index 88d97d4,4ca36fa..0107c47 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@@ -772,14 -735,8 +772,14 @@@ int chase_symlinks(const char *path, co if (fstat(child, &st) < 0) return -errno; + if ((flags & CHASE_SAFE) && + !safe_transition(&previous_stat, &st)) + return -EPERM; + + previous_stat = st; + if ((flags & CHASE_NO_AUTOFS) && - fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0) + fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0) return -EREMOTE; if (S_ISLNK(st.st_mode)) { diff --cc src/basic/missing_syscall.h index 9b84d46,fd82c11..6d4827c --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@@ -340,10 -318,10 +341,12 @@@ static inline ssize_t missing_copy_file return -1; # endif } + +# define copy_file_range missing_copy_file_range #endif + /* ======================================================================= */ + #if !HAVE_BPF # ifndef __NR_bpf # if defined __i386__ diff --cc src/basic/unit-def.c index 0000000,387533f..6a1fc95 mode 000000,100644..100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@@ -1,0 -1,290 +1,305 @@@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + /*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" + #include "bus-label.h" + #include "string-table.h" + #include "unit-def.h" + #include "unit-name.h" + + char *unit_dbus_path_from_name(const char *name) { + _cleanup_free_ char *e = NULL; + + assert(name); + + e = bus_label_escape(name); + if (!e) + return NULL; + + return strappend("/org/freedesktop/systemd1/unit/", e); + } + + int unit_name_from_dbus_path(const char *path, char **name) { + const char *e; + char *n; + + e = startswith(path, "/org/freedesktop/systemd1/unit/"); + if (!e) + return -EINVAL; + + n = bus_label_unescape(e); + if (!n) + return -ENOMEM; + + *name = n; + return 0; + } + + const char* unit_dbus_interface_from_type(UnitType t) { + + static const char *const table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "org.freedesktop.systemd1.Service", + [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket", ++ [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName", + [UNIT_TARGET] = "org.freedesktop.systemd1.Target", + [UNIT_DEVICE] = "org.freedesktop.systemd1.Device", + [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount", + [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount", + [UNIT_SWAP] = "org.freedesktop.systemd1.Swap", + [UNIT_TIMER] = "org.freedesktop.systemd1.Timer", + [UNIT_PATH] = "org.freedesktop.systemd1.Path", + [UNIT_SLICE] = "org.freedesktop.systemd1.Slice", + [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope", + }; + + if (t < 0) + return NULL; + if (t >= _UNIT_TYPE_MAX) + return NULL; + + return table[t]; + } + + const char *unit_dbus_interface_from_name(const char *name) { + UnitType t; + + t = unit_name_to_type(name); + if (t < 0) + return NULL; + + return unit_dbus_interface_from_type(t); + } + + static const char* const unit_type_table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "service", + [UNIT_SOCKET] = "socket", ++ [UNIT_BUSNAME] = "busname", + [UNIT_TARGET] = "target", + [UNIT_DEVICE] = "device", + [UNIT_MOUNT] = "mount", + [UNIT_AUTOMOUNT] = "automount", + [UNIT_SWAP] = "swap", + [UNIT_TIMER] = "timer", + [UNIT_PATH] = "path", + [UNIT_SLICE] = "slice", + [UNIT_SCOPE] = "scope", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); + + static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { + [UNIT_STUB] = "stub", + [UNIT_LOADED] = "loaded", + [UNIT_NOT_FOUND] = "not-found", + [UNIT_ERROR] = "error", + [UNIT_MERGED] = "merged", + [UNIT_MASKED] = "masked" + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); + + static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", + [UNIT_INACTIVE] = "inactive", + [UNIT_FAILED] = "failed", + [UNIT_ACTIVATING] = "activating", + [UNIT_DEACTIVATING] = "deactivating" + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); + + static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = "dead", + [AUTOMOUNT_WAITING] = "waiting", + [AUTOMOUNT_RUNNING] = "running", + [AUTOMOUNT_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); + ++static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { ++ [BUSNAME_DEAD] = "dead", ++ [BUSNAME_MAKING] = "making", ++ [BUSNAME_REGISTERED] = "registered", ++ [BUSNAME_LISTENING] = "listening", ++ [BUSNAME_RUNNING] = "running", ++ [BUSNAME_SIGTERM] = "sigterm", ++ [BUSNAME_SIGKILL] = "sigkill", ++ [BUSNAME_FAILED] = "failed", ++}; ++ ++DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); ++ + static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_TENTATIVE] = "tentative", + [DEVICE_PLUGGED] = "plugged", + }; + + DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); + + static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTING_DONE] = "mounting-done", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_REMOUNTING] = "remounting", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", + [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", + [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", + [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + + static const char* const path_state_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = "dead", + [PATH_WAITING] = "waiting", + [PATH_RUNNING] = "running", + [PATH_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); + + static const char* const scope_state_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = "dead", + [SCOPE_RUNNING] = "running", + [SCOPE_ABANDONED] = "abandoned", + [SCOPE_STOP_SIGTERM] = "stop-sigterm", + [SCOPE_STOP_SIGKILL] = "stop-sigkill", + [SCOPE_FAILED] = "failed", + }; + + DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); + + static const char* const service_state_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = "dead", + [SERVICE_START_PRE] = "start-pre", + [SERVICE_START] = "start", + [SERVICE_START_POST] = "start-post", + [SERVICE_RUNNING] = "running", + [SERVICE_EXITED] = "exited", + [SERVICE_RELOAD] = "reload", + [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGABRT] = "stop-sigabrt", + [SERVICE_STOP_SIGTERM] = "stop-sigterm", + [SERVICE_STOP_SIGKILL] = "stop-sigkill", + [SERVICE_STOP_POST] = "stop-post", + [SERVICE_FINAL_SIGTERM] = "final-sigterm", + [SERVICE_FINAL_SIGKILL] = "final-sigkill", + [SERVICE_FAILED] = "failed", + [SERVICE_AUTO_RESTART] = "auto-restart", + }; + + DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + + static const char* const slice_state_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = "dead", + [SLICE_ACTIVE] = "active" + }; + + DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); + + static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = "dead", + [SOCKET_START_PRE] = "start-pre", + [SOCKET_START_CHOWN] = "start-chown", + [SOCKET_START_POST] = "start-post", + [SOCKET_LISTENING] = "listening", + [SOCKET_RUNNING] = "running", + [SOCKET_STOP_PRE] = "stop-pre", + [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", + [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", + [SOCKET_STOP_POST] = "stop-post", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", + [SOCKET_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + + static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = "dead", + [SWAP_ACTIVATING] = "activating", + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + + static const char* const target_state_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = "dead", + [TARGET_ACTIVE] = "active" + }; + + DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); + + static const char* const timer_state_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = "dead", + [TIMER_WAITING] = "waiting", + [TIMER_RUNNING] = "running", + [TIMER_ELAPSED] = "elapsed", + [TIMER_FAILED] = "failed" + }; + + DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); + + static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { + [UNIT_REQUIRES] = "Requires", + [UNIT_REQUISITE] = "Requisite", + [UNIT_WANTS] = "Wants", + [UNIT_BINDS_TO] = "BindsTo", + [UNIT_PART_OF] = "PartOf", + [UNIT_REQUIRED_BY] = "RequiredBy", + [UNIT_REQUISITE_OF] = "RequisiteOf", + [UNIT_WANTED_BY] = "WantedBy", + [UNIT_BOUND_BY] = "BoundBy", + [UNIT_CONSISTS_OF] = "ConsistsOf", + [UNIT_CONFLICTS] = "Conflicts", + [UNIT_CONFLICTED_BY] = "ConflictedBy", + [UNIT_BEFORE] = "Before", + [UNIT_AFTER] = "After", + [UNIT_ON_FAILURE] = "OnFailure", + [UNIT_TRIGGERS] = "Triggers", + [UNIT_TRIGGERED_BY] = "TriggeredBy", + [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo", + [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom", + [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf", + [UNIT_REFERENCES] = "References", + [UNIT_REFERENCED_BY] = "ReferencedBy", + }; + + DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); + + static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { + [NOTIFY_NONE] = "none", + [NOTIFY_MAIN] = "main", + [NOTIFY_EXEC] = "exec", + [NOTIFY_ALL] = "all" + }; + + DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); diff --cc src/basic/unit-def.h index 0000000,c142e06..e7aacbd mode 000000,100644..100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@@ -1,0 -1,302 +1,319 @@@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + #pragma once + + /*** + This file is part of systemd. + + Copyright 2010 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 + + #include "macro.h" + + typedef enum UnitType { + UNIT_SERVICE = 0, + UNIT_SOCKET, ++ UNIT_BUSNAME, + UNIT_TARGET, + UNIT_DEVICE, + UNIT_MOUNT, + UNIT_AUTOMOUNT, + UNIT_SWAP, + UNIT_TIMER, + UNIT_PATH, + UNIT_SLICE, + UNIT_SCOPE, + _UNIT_TYPE_MAX, + _UNIT_TYPE_INVALID = -1 + } UnitType; + + typedef enum UnitLoadState { + UNIT_STUB = 0, + UNIT_LOADED, + UNIT_NOT_FOUND, + UNIT_ERROR, + UNIT_MERGED, + UNIT_MASKED, + _UNIT_LOAD_STATE_MAX, + _UNIT_LOAD_STATE_INVALID = -1 + } UnitLoadState; + + typedef enum UnitActiveState { + UNIT_ACTIVE, + UNIT_RELOADING, + UNIT_INACTIVE, + UNIT_FAILED, + UNIT_ACTIVATING, + UNIT_DEACTIVATING, + _UNIT_ACTIVE_STATE_MAX, + _UNIT_ACTIVE_STATE_INVALID = -1 + } UnitActiveState; + + typedef enum AutomountState { + AUTOMOUNT_DEAD, + AUTOMOUNT_WAITING, + AUTOMOUNT_RUNNING, + AUTOMOUNT_FAILED, + _AUTOMOUNT_STATE_MAX, + _AUTOMOUNT_STATE_INVALID = -1 + } AutomountState; + ++typedef enum BusNameState { ++ BUSNAME_DEAD, ++ BUSNAME_MAKING, ++ BUSNAME_REGISTERED, ++ BUSNAME_LISTENING, ++ BUSNAME_RUNNING, ++ BUSNAME_SIGTERM, ++ BUSNAME_SIGKILL, ++ BUSNAME_FAILED, ++ _BUSNAME_STATE_MAX, ++ _BUSNAME_STATE_INVALID = -1 ++} BusNameState; ++ + /* We simply watch devices, we cannot plug/unplug them. That + * simplifies the state engine greatly */ + typedef enum DeviceState { + DEVICE_DEAD, + DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ + DEVICE_PLUGGED, /* announced by udev */ + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 + } DeviceState; + + typedef enum MountState { + MOUNT_DEAD, + MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ + MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ + MOUNT_MOUNTED, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED, + _MOUNT_STATE_MAX, + _MOUNT_STATE_INVALID = -1 + } MountState; + + typedef enum PathState { + PATH_DEAD, + PATH_WAITING, + PATH_RUNNING, + PATH_FAILED, + _PATH_STATE_MAX, + _PATH_STATE_INVALID = -1 + } PathState; + + typedef enum ScopeState { + SCOPE_DEAD, + SCOPE_RUNNING, + SCOPE_ABANDONED, + SCOPE_STOP_SIGTERM, + SCOPE_STOP_SIGKILL, + SCOPE_FAILED, + _SCOPE_STATE_MAX, + _SCOPE_STATE_INVALID = -1 + } ScopeState; + + typedef enum ServiceState { + SERVICE_DEAD, + SERVICE_START_PRE, + SERVICE_START, + SERVICE_START_POST, + SERVICE_RUNNING, + SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ + SERVICE_RELOAD, + SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ + SERVICE_STOP_SIGABRT, /* Watchdog timeout */ + SERVICE_STOP_SIGTERM, + SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ + SERVICE_FINAL_SIGKILL, + SERVICE_FAILED, + SERVICE_AUTO_RESTART, + _SERVICE_STATE_MAX, + _SERVICE_STATE_INVALID = -1 + } ServiceState; + + typedef enum SliceState { + SLICE_DEAD, + SLICE_ACTIVE, + _SLICE_STATE_MAX, + _SLICE_STATE_INVALID = -1 + } SliceState; + + typedef enum SocketState { + SOCKET_DEAD, + SOCKET_START_PRE, + SOCKET_START_CHOWN, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL, + SOCKET_FAILED, + _SOCKET_STATE_MAX, + _SOCKET_STATE_INVALID = -1 + } SocketState; + + typedef enum SwapState { + SWAP_DEAD, + SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, + _SWAP_STATE_MAX, + _SWAP_STATE_INVALID = -1 + } SwapState; + + typedef enum TargetState { + TARGET_DEAD, + TARGET_ACTIVE, + _TARGET_STATE_MAX, + _TARGET_STATE_INVALID = -1 + } TargetState; + + typedef enum TimerState { + TIMER_DEAD, + TIMER_WAITING, + TIMER_RUNNING, + TIMER_ELAPSED, + TIMER_FAILED, + _TIMER_STATE_MAX, + _TIMER_STATE_INVALID = -1 + } TimerState; + + typedef enum UnitDependency { + /* Positive dependencies */ + UNIT_REQUIRES, + UNIT_REQUISITE, + UNIT_WANTS, + UNIT_BINDS_TO, + UNIT_PART_OF, + + /* Inverse of the above */ + UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */ + UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */ + UNIT_WANTED_BY, /* inverse of 'wants' */ + UNIT_BOUND_BY, /* inverse of 'binds_to' */ + UNIT_CONSISTS_OF, /* inverse of 'part_of' */ + + /* Negative dependencies */ + UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ + UNIT_CONFLICTED_BY, + + /* Order */ + UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */ + UNIT_AFTER, + + /* On Failure */ + UNIT_ON_FAILURE, + + /* Triggers (i.e. a socket triggers a service) */ + UNIT_TRIGGERS, + UNIT_TRIGGERED_BY, + + /* Propagate reloads */ + UNIT_PROPAGATES_RELOAD_TO, + UNIT_RELOAD_PROPAGATED_FROM, + + /* Joins namespace of */ + UNIT_JOINS_NAMESPACE_OF, + + /* Reference information for GC logic */ + UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ + UNIT_REFERENCED_BY, + + _UNIT_DEPENDENCY_MAX, + _UNIT_DEPENDENCY_INVALID = -1 + } UnitDependency; + + typedef enum NotifyAccess { + NOTIFY_NONE, + NOTIFY_ALL, + NOTIFY_MAIN, + NOTIFY_EXEC, + _NOTIFY_ACCESS_MAX, + _NOTIFY_ACCESS_INVALID = -1 + } NotifyAccess; + + char *unit_dbus_path_from_name(const char *name); + int unit_name_from_dbus_path(const char *path, char **name); + + const char* unit_dbus_interface_from_type(UnitType t); + const char *unit_dbus_interface_from_name(const char *name); + + const char *unit_type_to_string(UnitType i) _const_; + UnitType unit_type_from_string(const char *s) _pure_; + + const char *unit_load_state_to_string(UnitLoadState i) _const_; + UnitLoadState unit_load_state_from_string(const char *s) _pure_; + + const char *unit_active_state_to_string(UnitActiveState i) _const_; + UnitActiveState unit_active_state_from_string(const char *s) _pure_; + + const char* automount_state_to_string(AutomountState i) _const_; + AutomountState automount_state_from_string(const char *s) _pure_; + ++const char* busname_state_to_string(BusNameState i) _const_; ++BusNameState busname_state_from_string(const char *s) _pure_; ++ + const char* device_state_to_string(DeviceState i) _const_; + DeviceState device_state_from_string(const char *s) _pure_; + + const char* mount_state_to_string(MountState i) _const_; + MountState mount_state_from_string(const char *s) _pure_; + + const char* path_state_to_string(PathState i) _const_; + PathState path_state_from_string(const char *s) _pure_; + + const char* scope_state_to_string(ScopeState i) _const_; + ScopeState scope_state_from_string(const char *s) _pure_; + + const char* service_state_to_string(ServiceState i) _const_; + ServiceState service_state_from_string(const char *s) _pure_; + + const char* slice_state_to_string(SliceState i) _const_; + SliceState slice_state_from_string(const char *s) _pure_; + + const char* socket_state_to_string(SocketState i) _const_; + SocketState socket_state_from_string(const char *s) _pure_; + + const char* swap_state_to_string(SwapState i) _const_; + SwapState swap_state_from_string(const char *s) _pure_; + + const char* target_state_to_string(TargetState i) _const_; + TargetState target_state_from_string(const char *s) _pure_; + + const char *timer_state_to_string(TimerState i) _const_; + TimerState timer_state_from_string(const char *s) _pure_; + + const char *unit_dependency_to_string(UnitDependency i) _const_; + UnitDependency unit_dependency_from_string(const char *s) _pure_; + + const char* notify_access_to_string(NotifyAccess i) _const_; + NotifyAccess notify_access_from_string(const char *s) _pure_; diff --cc src/busctl/busctl.c index 30f0fed,7a8d6ba..58bb472 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@@ -18,8 -19,8 +19,10 @@@ ***/ #include + #include + +#include + #include "sd-bus.h" #include "alloc-util.h" diff --cc src/core/busname.c index 0826f2f,0000000..e06f2f4 mode 100644,000000..100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@@ -1,1081 -1,0 +1,1082 @@@ +/*** + This file is part of systemd. + + Copyright 2013 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 +#include + +#include "alloc-util.h" +#include "bus-internal.h" +#include "bus-kernel.h" +#include "bus-policy.h" +#include "bus-util.h" +#include "busname.h" +#include "dbus-busname.h" +#include "fd-util.h" +#include "format-util.h" +#include "parse-util.h" +#include "process-util.h" +#include "service.h" +#include "signal-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" + +static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = UNIT_INACTIVE, + [BUSNAME_MAKING] = UNIT_ACTIVATING, + [BUSNAME_REGISTERED] = UNIT_ACTIVE, + [BUSNAME_LISTENING] = UNIT_ACTIVE, + [BUSNAME_RUNNING] = UNIT_ACTIVE, + [BUSNAME_SIGTERM] = UNIT_DEACTIVATING, + [BUSNAME_SIGKILL] = UNIT_DEACTIVATING, + [BUSNAME_FAILED] = UNIT_FAILED +}; + +static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); +static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); + +static void busname_init(Unit *u) { + BusName *n = BUSNAME(u); + + assert(u); + assert(u->load_state == UNIT_STUB); + + n->starter_fd = -1; + n->accept_fd = true; + n->activating = true; + + n->timeout_usec = u->manager->default_timeout_start_usec; +} + +static void busname_unwatch_control_pid(BusName *n) { + assert(n); + + if (n->control_pid <= 0) + return; + + unit_unwatch_pid(UNIT(n), n->control_pid); + n->control_pid = 0; +} + +static void busname_free_policy(BusName *n) { + BusNamePolicy *p; + + assert(n); + + while ((p = n->policy)) { + LIST_REMOVE(policy, n->policy, p); + + free(p->name); + free(p); + } +} + +static void busname_close_fd(BusName *n) { + assert(n); + + n->starter_event_source = sd_event_source_unref(n->starter_event_source); + n->starter_fd = safe_close(n->starter_fd); +} + +static void busname_done(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + n->name = mfree(n->name); + + busname_free_policy(n); + busname_unwatch_control_pid(n); + busname_close_fd(n); + + unit_ref_unset(&n->service); + + n->timer_event_source = sd_event_source_unref(n->timer_event_source); +} + +static int busname_arm_timer(BusName *n, usec_t usec) { + int r; + + assert(n); + + if (n->timer_event_source) { + r = sd_event_source_set_time(n->timer_event_source, usec); + if (r < 0) + return r; + + return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT); + } + + if (usec == USEC_INFINITY) + return 0; + + r = sd_event_add_time( + UNIT(n)->manager->event, + &n->timer_event_source, + CLOCK_MONOTONIC, + usec, 0, + busname_dispatch_timer, n); + if (r < 0) + return r; + + (void) sd_event_source_set_description(n->timer_event_source, "busname-timer"); + + return 0; +} + +static int busname_add_default_default_dependencies(BusName *n) { + int r; + + assert(n); + - r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true); ++ r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); + if (r < 0) + return r; + + if (MANAGER_IS_SYSTEM(UNIT(n)->manager)) { - r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); ++ r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); + if (r < 0) + return r; + } + - return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); ++ return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true, UNIT_DEPENDENCY_DEFAULT); +} + +static int busname_add_extras(BusName *n) { + Unit *u = UNIT(n); + int r; + + assert(n); + + if (!n->name) { + r = unit_name_to_prefix(u->id, &n->name); + if (r < 0) + return r; + } + + if (!u->description) { + r = unit_set_description(u, n->name); + if (r < 0) + return r; + } + + if (n->activating) { + if (!UNIT_DEREF(n->service)) { + Unit *x; + + r = unit_load_related_unit(u, ".service", &x); + if (r < 0) + return r; + + unit_ref_set(&n->service, x); + } + - r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true); ++ r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true, UNIT_DEPENDENCY_IMPLICIT); + if (r < 0) + return r; + } + + if (u->default_dependencies) { + r = busname_add_default_default_dependencies(n); + if (r < 0) + return r; + } + + return 0; +} + +static int busname_verify(BusName *n) { + char *e; + + assert(n); + + if (UNIT(n)->load_state != UNIT_LOADED) + return 0; + + if (!service_name_is_valid(n->name)) { + log_unit_error(UNIT(n), "Name= setting is not a valid service name Refusing."); + return -EINVAL; + } + + e = strjoina(n->name, ".busname"); + if (!unit_has_name(UNIT(n), e)) { + log_unit_error(UNIT(n), "Name= setting doesn't match unit name. Refusing."); + return -EINVAL; + } + + return 0; +} + +static int busname_load(Unit *u) { + BusName *n = BUSNAME(u); + int r; + + assert(u); + assert(u->load_state == UNIT_STUB); + + r = unit_load_fragment_and_dropin(u); + if (r < 0) + return r; + + if (u->load_state == UNIT_LOADED) { + /* This is a new unit? Then let's add in some extras */ + r = busname_add_extras(n); + if (r < 0) + return r; + } + + return busname_verify(n); +} + +static void busname_dump(Unit *u, FILE *f, const char *prefix) { + BusName *n = BUSNAME(u); + + assert(n); + assert(f); + + fprintf(f, + "%sBus Name State: %s\n" + "%sResult: %s\n" + "%sName: %s\n" + "%sActivating: %s\n" + "%sAccept FD: %s\n", + prefix, busname_state_to_string(n->state), + prefix, busname_result_to_string(n->result), + prefix, n->name, + prefix, yes_no(n->activating), + prefix, yes_no(n->accept_fd)); + + if (n->control_pid > 0) + fprintf(f, + "%sControl PID: "PID_FMT"\n", + prefix, n->control_pid); +} + +static void busname_unwatch_fd(BusName *n) { + int r; + + assert(n); + + if (!n->starter_event_source) + return; + + r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_OFF); + if (r < 0) + log_unit_debug_errno(UNIT(n), r, "Failed to disable event source: %m"); +} + +static int busname_watch_fd(BusName *n) { + int r; + + assert(n); + + if (n->starter_fd < 0) + return 0; + + if (n->starter_event_source) { + r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_ON); + if (r < 0) + goto fail; + } else { + r = sd_event_add_io(UNIT(n)->manager->event, &n->starter_event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n); + if (r < 0) + goto fail; + + (void) sd_event_source_set_description(n->starter_event_source, "busname-starter"); + } + + return 0; + +fail: + log_unit_warning_errno(UNIT(n), r, "Failed to watch starter fd: %m"); + busname_unwatch_fd(n); + return r; +} + +static int busname_open_fd(BusName *n) { + _cleanup_free_ char *path = NULL; + const char *mode; + + assert(n); + + if (n->starter_fd >= 0) + return 0; + + mode = MANAGER_IS_SYSTEM(UNIT(n)->manager) ? "system" : "user"; + n->starter_fd = bus_kernel_open_bus_fd(mode, &path); + if (n->starter_fd < 0) + return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus"); + + return 0; +} + +static void busname_set_state(BusName *n, BusNameState state) { + BusNameState old_state; + assert(n); + + old_state = n->state; + n->state = state; + + if (!IN_SET(state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { + n->timer_event_source = sd_event_source_unref(n->timer_event_source); + busname_unwatch_control_pid(n); + } + + if (state != BUSNAME_LISTENING) + busname_unwatch_fd(n); + + if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_MAKING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) + busname_close_fd(n); + + if (state != old_state) + log_unit_debug(UNIT(n), "Changed %s -> %s", busname_state_to_string(old_state), busname_state_to_string(state)); + + unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true); +} + +static int busname_coldplug(Unit *u) { + BusName *n = BUSNAME(u); + int r; + + assert(n); + assert(n->state == BUSNAME_DEAD); + + if (n->deserialized_state == n->state) + return 0; + + if (n->control_pid > 0 && + pid_is_unwaited(n->control_pid) && + IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { + + r = unit_watch_pid(UNIT(n), n->control_pid); + if (r < 0) + return r; + + r = busname_arm_timer(n, usec_add(u->state_change_timestamp.monotonic, n->timeout_usec)); + if (r < 0) + return r; + } + + if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) { + r = busname_open_fd(n); + if (r < 0) + return r; + } + + if (n->deserialized_state == BUSNAME_LISTENING) { + r = busname_watch_fd(n); + if (r < 0) + return r; + } + + busname_set_state(n, n->deserialized_state); + return 0; +} + +static int busname_make_starter(BusName *n, pid_t *_pid) { + pid_t pid; + int r; + + r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec)); + if (r < 0) + goto fail; + + /* We have to resolve the user/group names out-of-process, + * hence let's fork here. It's messy, but well, what can we + * do? */ + + pid = fork(); + if (pid < 0) + return -errno; + + if (pid == 0) { + int ret; + + (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1); + (void) ignore_signals(SIGPIPE, -1); + log_forget_fds(); + + r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, n->policy, n->policy_world); + if (r < 0) { + ret = EXIT_MAKE_STARTER; + goto fail_child; + } + + _exit(0); + + fail_child: + log_open(); + log_error_errno(r, "Failed to create starter connection at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD)); + + _exit(ret); + } + + r = unit_watch_pid(UNIT(n), pid); + if (r < 0) + goto fail; + + *_pid = pid; + return 0; + +fail: + n->timer_event_source = sd_event_source_unref(n->timer_event_source); + return r; +} + +static void busname_enter_dead(BusName *n, BusNameResult f) { + assert(n); + + if (n->result == BUSNAME_SUCCESS) + n->result = f; + + busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD); +} + +static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f) { + KillContext kill_context = {}; + int r; + + assert(n); + + if (n->result == BUSNAME_SUCCESS) + n->result = f; + + kill_context_init(&kill_context); + + r = unit_kill_context(UNIT(n), + &kill_context, + state != BUSNAME_SIGTERM ? KILL_KILL : KILL_TERMINATE, + -1, + n->control_pid, + false); + if (r < 0) { + log_unit_warning_errno(UNIT(n), r, "Failed to kill control process: %m"); + goto fail; + } + + if (r > 0) { + r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec)); + if (r < 0) { + log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m"); + goto fail; + } + + busname_set_state(n, state); + } else if (state == BUSNAME_SIGTERM) + busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_SUCCESS); + else + busname_enter_dead(n, BUSNAME_SUCCESS); + + return; + +fail: + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); +} + +static void busname_enter_listening(BusName *n) { + int r; + + assert(n); + + if (n->activating) { + r = busname_watch_fd(n); + if (r < 0) { + log_unit_warning_errno(UNIT(n), r, "Failed to watch names: %m"); + goto fail; + } + + busname_set_state(n, BUSNAME_LISTENING); + } else + busname_set_state(n, BUSNAME_REGISTERED); + + return; + +fail: + busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_RESOURCES); +} + +static void busname_enter_making(BusName *n) { + int r; + + assert(n); + + r = busname_open_fd(n); + if (r < 0) + goto fail; + + if (n->policy) { + /* If there is a policy, we need to resolve user/group + * names, which we can't do from PID1, hence let's + * fork. */ + busname_unwatch_control_pid(n); + + r = busname_make_starter(n, &n->control_pid); + if (r < 0) { + log_unit_warning_errno(UNIT(n), r, "Failed to fork 'making' task: %m"); + goto fail; + } + + busname_set_state(n, BUSNAME_MAKING); + } else { + /* If there is no policy, we can do everything + * directly from PID 1, hence do so. */ + + r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, NULL, n->policy_world); + if (r < 0) { + log_unit_warning_errno(UNIT(n), r, "Failed to make starter: %m"); + goto fail; + } + + busname_enter_listening(n); + } + + return; + +fail: + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); +} + +static void busname_enter_running(BusName *n) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + bool pending = false; + Unit *other; + Iterator i; + int r; ++ void *v; + + assert(n); + + if (!n->activating) + return; + + /* We don't take connections anymore if we are supposed to + * shut down anyway */ + + if (unit_stop_pending(UNIT(n))) { + log_unit_debug(UNIT(n), "Suppressing activation request since unit stop is scheduled."); + + /* Flush all queued activation reqeuest by closing and reopening the connection */ + bus_kernel_drop_one(n->starter_fd); + + busname_enter_listening(n); + return; + } + + /* If there's already a start pending don't bother to do + * anything */ - SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i) ++ HASHMAP_FOREACH_KEY(v, other, UNIT(n)->dependencies[UNIT_TRIGGERS], i) + if (unit_active_or_pending(other)) { + pending = true; + break; + } + + if (!pending) { + if (!UNIT_ISSET(n->service)) { + log_unit_error(UNIT(n), "Service to activate vanished, refusing activation."); + r = -ENOENT; + goto fail; + } + + r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL); + if (r < 0) + goto fail; + } + + busname_set_state(n, BUSNAME_RUNNING); + return; + +fail: + log_unit_warning(UNIT(n), "Failed to queue service startup job: %s", bus_error_message(&error, r)); + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); +} + +static int busname_start(Unit *u) { + BusName *n = BUSNAME(u); + int r; + + assert(n); + + /* We cannot fulfill this request right now, try again later + * please! */ + if (IN_SET(n->state, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) + return -EAGAIN; + + /* Already on it! */ + if (n->state == BUSNAME_MAKING) + return 0; + + if (n->activating && UNIT_ISSET(n->service)) { + Service *service; + + service = SERVICE(UNIT_DEREF(n->service)); + + if (UNIT(service)->load_state != UNIT_LOADED) { + log_unit_error(u, "Bus service %s not loaded, refusing.", UNIT(service)->id); + return -ENOENT; + } + } + + assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED)); + + r = unit_start_limit_test(u); + if (r < 0) { + busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT); + return r; + } + + r = unit_acquire_invocation_id(u); + if (r < 0) + return r; + + n->result = BUSNAME_SUCCESS; + busname_enter_making(n); + + return 1; +} + +static int busname_stop(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + /* Already on it */ + if (IN_SET(n->state, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) + return 0; + + /* If there's already something running, we go directly into + * kill mode. */ + + if (n->state == BUSNAME_MAKING) { + busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_SUCCESS); + return -EAGAIN; + } + + assert(IN_SET(n->state, BUSNAME_REGISTERED, BUSNAME_LISTENING, BUSNAME_RUNNING)); + + busname_enter_dead(n, BUSNAME_SUCCESS); + return 1; +} + +static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { + BusName *n = BUSNAME(u); + int r; + + assert(n); + assert(f); + assert(fds); + + unit_serialize_item(u, f, "state", busname_state_to_string(n->state)); + unit_serialize_item(u, f, "result", busname_result_to_string(n->result)); + + if (n->control_pid > 0) + unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid); + + r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd); + if (r < 0) + return r; + + return 0; +} + +static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { + BusName *n = BUSNAME(u); + + assert(n); + assert(key); + assert(value); + + if (streq(key, "state")) { + BusNameState state; + + state = busname_state_from_string(value); + if (state < 0) + log_unit_debug(u, "Failed to parse state value: %s", value); + else + n->deserialized_state = state; + + } else if (streq(key, "result")) { + BusNameResult f; + + f = busname_result_from_string(value); + if (f < 0) + log_unit_debug(u, "Failed to parse result value: %s", value); + else if (f != BUSNAME_SUCCESS) + n->result = f; + + } else if (streq(key, "control-pid")) { + pid_t pid; + + if (parse_pid(value, &pid) < 0) + log_unit_debug(u, "Failed to parse control-pid value: %s", value); + else + n->control_pid = pid; + } else if (streq(key, "starter-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse starter fd value: %s", value); + else { + safe_close(n->starter_fd); + n->starter_fd = fdset_remove(fds, fd); + } + } else + log_unit_debug(u, "Unknown serialization key: %s", key); + + return 0; +} + +_pure_ static UnitActiveState busname_active_state(Unit *u) { + assert(u); + + return state_translation_table[BUSNAME(u)->state]; +} + +_pure_ static const char *busname_sub_state_to_string(Unit *u) { + assert(u); + + return busname_state_to_string(BUSNAME(u)->state); +} + +static int busname_peek_message(BusName *n) { + struct kdbus_cmd_recv cmd_recv = { + .size = sizeof(cmd_recv), + .flags = KDBUS_RECV_PEEK, + }; + struct kdbus_cmd_free cmd_free = { + .size = sizeof(cmd_free), + }; + const char *comm = NULL; + struct kdbus_item *d; + struct kdbus_msg *k; + size_t start, ps, sz, delta; + void *p = MAP_FAILED; + pid_t pid = 0; + int r; + + /* Generate a friendly debug log message about which process + * caused triggering of this bus name. This simply peeks the + * metadata of the first queued message and logs it. */ + + assert(n); + + /* Let's shortcut things a bit, if debug logging is turned off + * anyway. */ + + if (log_get_max_level() < LOG_DEBUG) + return 0; + + r = ioctl(n->starter_fd, KDBUS_CMD_RECV, &cmd_recv); + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) + return 0; + + return log_unit_error_errno(UNIT(n), errno, "Failed to query activation message: %m"); + } + + /* We map as late as possible, and unmap imemdiately after + * use. On 32bit address space is scarce and we want to be + * able to handle a lot of activator connections at the same + * time, and hence shouldn't keep the mmap()s around for + * longer than necessary. */ + + ps = page_size(); + start = (cmd_recv.msg.offset / ps) * ps; + delta = cmd_recv.msg.offset - start; + sz = PAGE_ALIGN(delta + cmd_recv.msg.msg_size); + + p = mmap(NULL, sz, PROT_READ, MAP_SHARED, n->starter_fd, start); + if (p == MAP_FAILED) { + r = log_unit_error_errno(UNIT(n), errno, "Failed to map activation message: %m"); + goto finish; + } + + k = (struct kdbus_msg *) ((uint8_t *) p + delta); + KDBUS_ITEM_FOREACH(d, k, items) { + switch (d->type) { + + case KDBUS_ITEM_PIDS: + pid = d->pids.pid; + break; + + case KDBUS_ITEM_PID_COMM: + comm = d->str; + break; + } + } + + if (pid > 0) + log_unit_debug(UNIT(n), "Activation triggered by process " PID_FMT " (%s)", pid, strna(comm)); + + r = 0; + +finish: + if (p != MAP_FAILED) + (void) munmap(p, sz); + + cmd_free.offset = cmd_recv.msg.offset; + if (ioctl(n->starter_fd, KDBUS_CMD_FREE, &cmd_free) < 0) + log_unit_warning(UNIT(n), "Failed to free peeked message, ignoring: %m"); + + return r; +} + +static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + BusName *n = userdata; + + assert(n); + assert(fd >= 0); + + if (n->state != BUSNAME_LISTENING) + return 0; + + log_unit_debug(UNIT(n), "Activation request"); + + if (revents != EPOLLIN) { + log_unit_error(UNIT(n), "Got unexpected poll event (0x%x) on starter fd.", revents); + goto fail; + } + + busname_peek_message(n); + busname_enter_running(n); + return 0; +fail: + + busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES); + return 0; +} + +static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) { + BusName *n = BUSNAME(u); + BusNameResult f; + + assert(n); + assert(pid >= 0); + + if (pid != n->control_pid) + return; + + n->control_pid = 0; + + if (is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL)) + f = BUSNAME_SUCCESS; + else if (code == CLD_EXITED) + f = BUSNAME_FAILURE_EXIT_CODE; + else if (code == CLD_KILLED) + f = BUSNAME_FAILURE_SIGNAL; + else if (code == CLD_DUMPED) + f = BUSNAME_FAILURE_CORE_DUMP; + else + assert_not_reached("Unknown sigchld code"); + + log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0, + "Control process exited, code=%s status=%i", sigchld_code_to_string(code), status); + + if (n->result == BUSNAME_SUCCESS) + n->result = f; + + switch (n->state) { + + case BUSNAME_MAKING: + if (f == BUSNAME_SUCCESS) + busname_enter_listening(n); + else + busname_enter_signal(n, BUSNAME_SIGTERM, f); + break; + + case BUSNAME_SIGTERM: + case BUSNAME_SIGKILL: + busname_enter_dead(n, f); + break; + + default: + assert_not_reached("Uh, control process died at wrong time."); + } + + /* Notify clients about changed exit status */ + unit_add_to_dbus_queue(u); +} + +static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) { + BusName *n = BUSNAME(userdata); + + assert(n); + assert(n->timer_event_source == source); + + switch (n->state) { + + case BUSNAME_MAKING: + log_unit_warning(UNIT(n), "Making timed out. Terminating."); + busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_TIMEOUT); + break; + + case BUSNAME_SIGTERM: + log_unit_warning(UNIT(n), "Stopping timed out. Killing."); + busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_FAILURE_TIMEOUT); + break; + + case BUSNAME_SIGKILL: + log_unit_warning(UNIT(n), "Processes still around after SIGKILL. Ignoring."); + busname_enter_dead(n, BUSNAME_FAILURE_TIMEOUT); + break; + + default: + assert_not_reached("Timeout at wrong time."); + } + + return 0; +} + +static void busname_reset_failed(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + if (n->state == BUSNAME_FAILED) + busname_set_state(n, BUSNAME_DEAD); + + n->result = BUSNAME_SUCCESS; +} + +static void busname_trigger_notify(Unit *u, Unit *other) { + BusName *n = BUSNAME(u); + + assert(n); + assert(other); + + if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING)) + return; + + if (other->start_limit_hit) { + busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT); + return; + } + + if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) + return; + + if (IN_SET(SERVICE(other)->state, + SERVICE_DEAD, SERVICE_FAILED, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, + SERVICE_AUTO_RESTART)) + busname_enter_listening(n); + + if (SERVICE(other)->state == SERVICE_RUNNING) + busname_set_state(n, BUSNAME_RUNNING); +} + +static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { + return unit_kill_common(u, who, signo, -1, BUSNAME(u)->control_pid, error); +} + +static int busname_get_timeout(Unit *u, usec_t *timeout) { + BusName *n = BUSNAME(u); + usec_t t; + int r; + + if (!n->timer_event_source) + return 0; + + r = sd_event_source_get_time(n->timer_event_source, &t); + if (r < 0) + return r; + if (t == USEC_INFINITY) + return 0; + + *timeout = t; + return 1; +} + +static bool busname_supported(void) { + return is_kdbus_available(); +} + +static int busname_control_pid(Unit *u) { + BusName *n = BUSNAME(u); + + assert(n); + + return n->control_pid; +} + +static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { + [BUSNAME_SUCCESS] = "success", + [BUSNAME_FAILURE_RESOURCES] = "resources", + [BUSNAME_FAILURE_TIMEOUT] = "timeout", + [BUSNAME_FAILURE_EXIT_CODE] = "exit-code", + [BUSNAME_FAILURE_SIGNAL] = "signal", + [BUSNAME_FAILURE_CORE_DUMP] = "core-dump", + [BUSNAME_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult); + +const UnitVTable busname_vtable = { + .object_size = sizeof(BusName), + + .sections = + "Unit\0" + "BusName\0" + "Install\0", + .private_section = "BusName", + + .init = busname_init, + .done = busname_done, + .load = busname_load, + + .coldplug = busname_coldplug, + + .dump = busname_dump, + + .start = busname_start, + .stop = busname_stop, + + .kill = busname_kill, + + .get_timeout = busname_get_timeout, + + .serialize = busname_serialize, + .deserialize_item = busname_deserialize_item, + + .active_state = busname_active_state, + .sub_state_to_string = busname_sub_state_to_string, + + .sigchld_event = busname_sigchld_event, + + .trigger_notify = busname_trigger_notify, + + .reset_failed = busname_reset_failed, + + .supported = busname_supported, + + .control_pid = busname_control_pid, + + .bus_vtable = bus_busname_vtable, + + .status_message_formats = { + .finished_start_job = { + [JOB_DONE] = "Listening on %s.", + [JOB_FAILED] = "Failed to listen on %s.", + }, + .finished_stop_job = { + [JOB_DONE] = "Closed %s.", + [JOB_FAILED] = "Failed stopping %s.", + }, + }, +}; diff --cc src/core/execute.c index 2697132,f202467..01ec5b3 --- a/src/core/execute.c +++ b/src/core/execute.c @@@ -4069,14 -4102,26 +4150,34 @@@ void exec_context_dump(ExecContext *c, fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str); } + if (c->capabilities) { + _cleanup_cap_free_charp_ char *t; + + t = cap_to_text(c->capabilities, NULL); + if (t) + fprintf(f, "%sCapabilities: %s\n", prefix, t); + } + + if (c->log_level_max >= 0) { + _cleanup_free_ char *t = NULL; + + (void) log_level_to_string_alloc(c->log_level_max, &t); + + fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t)); + } + + if (c->n_log_extra_fields > 0) { + size_t j; + + for (j = 0; j < c->n_log_extra_fields; j++) { + fprintf(f, "%sLogExtraFields: ", prefix); + fwrite(c->log_extra_fields[j].iov_base, + 1, c->log_extra_fields[j].iov_len, + f); + fputc('\n', f); + } + } + if (c->secure_bits) { _cleanup_free_ char *str = NULL; diff --cc src/core/load-fragment-gperf.gperf.m4 index f8a0724,240f331..41287ac --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@@ -48,7 -54,9 +54,9 @@@ $1.SyslogIdentifier, config $1.SyslogFacility, config_parse_log_facility, 0, offsetof($1, exec_context.syslog_priority) $1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority) $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) + $1.LogLevelMax, config_parse_log_level, 0, offsetof($1, exec_context.log_level_max) + $1.LogExtraFields, config_parse_log_extra_fields, 0, offsetof($1, exec_context) -$1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context) +$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) $1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set) $1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set) @@@ -370,19 -381,10 +381,19 @@@ EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dn CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl m4_dnl +BusName.Name, config_parse_string, 0, offsetof(BusName, name) +BusName.Activating, config_parse_bool, 0, offsetof(BusName, activating) +BusName.Service, config_parse_busname_service, 0, 0 +BusName.AllowUser, config_parse_bus_policy, 0, 0 +BusName.AllowGroup, config_parse_bus_policy, 0, 0 +BusName.AllowWorld, config_parse_bus_policy_world, 0, offsetof(BusName, policy_world) +BusName.SELinuxContext, config_parse_exec_selinux_context, 0, 0 +BusName.AcceptFileDescriptors, config_parse_bool, 0, offsetof(BusName, accept_fd) +m4_dnl Mount.What, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.what) - Mount.Where, config_parse_path, 0, offsetof(Mount, where) + Mount.Where, config_parse_unit_path_printf, 0, offsetof(Mount, where) Mount.Options, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.options) - Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype) + Mount.Type, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.fstype) Mount.TimeoutSec, config_parse_sec_fix_0, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options) diff --cc src/core/main.c index 1e8a179,2ad5073..42aa1cf --- a/src/core/main.c +++ b/src/core/main.c @@@ -1387,283 -1444,839 +1444,833 @@@ static int fixup_environment(void) return 0; } - int main(int argc, char *argv[]) { - Manager *m = NULL; - int r, retval = EXIT_FAILURE; - usec_t before_startup, after_startup; - char timespan[FORMAT_TIMESPAN_MAX]; - FDSet *fds = NULL; - bool reexecute = false; - const char *shutdown_verb = NULL; - dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL; - dual_timestamp userspace_timestamp = DUAL_TIMESTAMP_NULL; - dual_timestamp kernel_timestamp = DUAL_TIMESTAMP_NULL; - dual_timestamp security_start_timestamp = DUAL_TIMESTAMP_NULL; - dual_timestamp security_finish_timestamp = DUAL_TIMESTAMP_NULL; - static char systemd[] = "systemd"; - bool skip_setup = false; - unsigned j; - bool loaded_policy = false; - bool arm_reboot_watchdog = false; - bool queue_default_job = false; - bool empty_etc = false; - char *switch_root_dir = NULL, *switch_root_init = NULL; - struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), saved_rlimit_memlock = RLIMIT_MAKE_CONST((rlim_t) -1); - const char *error_message = NULL; + static void redirect_telinit(int argc, char *argv[]) { + + /* This is compatibility support for SysV, where calling init as a user is identical to telinit. */ #if HAVE_SYSV_COMPAT - if (getpid_cached() != 1 && strstr(program_invocation_short_name, "init")) { - /* This is compatibility support for SysV, where - * calling init as a user is identical to telinit. */ + if (getpid_cached() == 1) + return; - execv(SYSTEMCTL_BINARY_PATH, argv); - log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m"); - return 1; - } - #endif + if (!strstr(program_invocation_short_name, "init")) + return; - dual_timestamp_from_monotonic(&kernel_timestamp, 0); - dual_timestamp_get(&userspace_timestamp); + execv(SYSTEMCTL_BINARY_PATH, argv); + log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m"); + exit(1); + #endif + } - /* Determine if this is a reexecution or normal bootup. We do - * the full command line parsing much later, so let's just - * have a quick peek here. */ - if (strv_find(argv+1, "--deserialize")) - skip_setup = true; + static int become_shutdown( + const char *shutdown_verb, + int retval) { - /* If we have switched root, do all the special setup - * things */ - if (strv_find(argv+1, "--switched-root")) - skip_setup = false; + char log_level[DECIMAL_STR_MAX(int) + 1], + exit_code[DECIMAL_STR_MAX(uint8_t) + 1]; - /* If we get started via the /sbin/init symlink then we are - called 'init'. After a subsequent reexecution we are then - called 'systemd'. That is confusing, hence let's call us - systemd right-away. */ - program_invocation_short_name = systemd; - (void) prctl(PR_SET_NAME, systemd); + const char* command_line[11] = { + SYSTEMD_SHUTDOWN_BINARY_PATH, + shutdown_verb, + "--log-level", log_level, + "--log-target", + }; - saved_argv = argv; - saved_argc = argc; + _cleanup_strv_free_ char **env_block = NULL; + size_t pos = 5; + int r; - log_set_upgrade_syslog_to_journal(true); + assert(shutdown_verb); + assert(!command_line[pos]); + env_block = strv_copy(environ); - if (getpid_cached() == 1) { - /* Disable the umask logic */ - umask(0); + xsprintf(log_level, "%d", log_get_max_level()); - /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is - * important so that we never end up logging to any foreign stderr, for example if we have to log in a - * child process right before execve()'ing the actual binary, at a point in time where socket - * activation stderr/stdout area already set up. */ - log_set_always_reopen_console(true); - } + switch (log_get_target()) { - if (getpid_cached() == 1 && detect_container() <= 0) { + case LOG_TARGET_KMSG: + case LOG_TARGET_JOURNAL_OR_KMSG: + case LOG_TARGET_SYSLOG_OR_KMSG: + command_line[pos++] = "kmsg"; + break; - /* Running outside of a container as PID 1 */ - arg_system = true; - log_set_target(LOG_TARGET_KMSG); - log_open(); + case LOG_TARGET_NULL: + command_line[pos++] = "null"; + break; - if (in_initrd()) - initrd_timestamp = userspace_timestamp; + case LOG_TARGET_CONSOLE: + default: + command_line[pos++] = "console"; + break; + }; - if (!skip_setup) { - r = mount_setup_early(); - if (r < 0) { - error_message = "Failed to mount early API filesystems"; - goto finish; - } + if (log_get_show_color()) + command_line[pos++] = "--log-color"; - dual_timestamp_get(&security_start_timestamp); - if (mac_selinux_setup(&loaded_policy) < 0) { - error_message = "Failed to load SELinux policy"; - goto finish; - } else if (mac_smack_setup(&loaded_policy) < 0) { - error_message = "Failed to load SMACK policy"; - goto finish; - } else if (ima_setup() < 0) { - error_message = "Failed to load IMA policy"; - goto finish; - } - dual_timestamp_get(&security_finish_timestamp); - } + if (log_get_show_location()) + command_line[pos++] = "--log-location"; - if (mac_selinux_init() < 0) { - error_message = "Failed to initialize SELinux policy"; - goto finish; - } + if (streq(shutdown_verb, "exit")) { + command_line[pos++] = "--exit-code"; + command_line[pos++] = exit_code; + xsprintf(exit_code, "%d", retval); + } - if (!skip_setup) { - if (clock_is_localtime(NULL) > 0) { - int min; - - /* - * The very first call of settimeofday() also does a time warp in the kernel. - * - * In the rtc-in-local time mode, we set the kernel's timezone, and rely on - * external tools to take care of maintaining the RTC and do all adjustments. - * This matches the behavior of Windows, which leaves the RTC alone if the - * registry tells that the RTC runs in UTC. - */ - r = clock_set_timezone(&min); - if (r < 0) - log_error_errno(r, "Failed to apply local time delta, ignoring: %m"); - else - log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); - } else if (!in_initrd()) { - /* - * Do a dummy very first call to seal the kernel's time warp magic. - * - * Do not call this from inside the initrd. The initrd might not - * carry /etc/adjtime with LOCAL, but the real system could be set up - * that way. In such case, we need to delay the time-warp or the sealing - * until we reach the real system. - * - * Do no set the kernel's timezone. The concept of local time cannot - * be supported reliably, the time will jump or be incorrect at every daylight - * saving time change. All kernel local time concepts will be treated - * as UTC that way. - */ - clock_reset_timewarp(); - } - } + assert(pos < ELEMENTSOF(command_line)); - /* Set the default for later on, but don't actually - * open the logs like this for now. Note that if we - * are transitioning from the initrd there might still - * be journal fd open, and we shouldn't attempt - * opening that before we parsed /proc/cmdline which - * might redirect output elsewhere. */ - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + if (streq(shutdown_verb, "reboot") && + arg_shutdown_watchdog > 0 && + arg_shutdown_watchdog != USEC_INFINITY) { - } else if (getpid_cached() == 1) { - /* Running inside a container, as PID 1 */ - arg_system = true; - log_set_target(LOG_TARGET_CONSOLE); - log_close_console(); /* force reopen of /dev/console */ - log_open(); + char *e; - /* For later on, see above... */ - log_set_target(LOG_TARGET_JOURNAL); + /* If we reboot let's set the shutdown + * watchdog and tell the shutdown binary to + * repeatedly ping it */ + r = watchdog_set_timeout(&arg_shutdown_watchdog); + watchdog_close(r < 0); - /* clear the kernel timestamp, - * because we are in a container */ - kernel_timestamp = DUAL_TIMESTAMP_NULL; - } else { - /* Running as user instance */ - arg_system = false; - log_set_target(LOG_TARGET_AUTO); - log_open(); + /* Tell the binary how often to ping, ignore failure */ + if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0) + (void) strv_consume(&env_block, e); - /* clear the kernel timestamp, - * because we are not PID 1 */ - kernel_timestamp = DUAL_TIMESTAMP_NULL; - } + if (arg_watchdog_device && + asprintf(&e, "WATCHDOG_DEVICE=%s", arg_watchdog_device) > 0) + (void) strv_consume(&env_block, e); + } else + watchdog_close(true); - if (getpid_cached() == 1) { - /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit) - * will process core dumps for system services by default. */ - if (setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0) - log_warning_errno(errno, "Failed to set RLIMIT_CORE: %m"); + /* Avoid the creation of new processes forked by the + * kernel; at this point, we will not listen to the + * signals anyway */ + if (detect_container() <= 0) + (void) cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER); - /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored - * until the systemd-coredump tool is enabled via sysctl. */ - if (!skip_setup) - (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); - } + execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block); + return -errno; + } - if (arg_system) { - if (fixup_environment() < 0) { - error_message = "Failed to fix up PID1 environment"; - goto finish; - } + static void initialize_clock(void) { + int r; - /* Try to figure out if we can use colors with the console. No - * need to do that for user instances since they never log - * into the console. */ - log_show_color(colors_enabled()); - r = make_null_stdio(); + if (clock_is_localtime(NULL) > 0) { + int min; + + /* + * The very first call of settimeofday() also does a time warp in the kernel. + * + * In the rtc-in-local time mode, we set the kernel's timezone, and rely on external tools to take care + * of maintaining the RTC and do all adjustments. This matches the behavior of Windows, which leaves + * the RTC alone if the registry tells that the RTC runs in UTC. + */ + r = clock_set_timezone(&min); if (r < 0) - log_warning_errno(r, "Failed to redirect standard streams to /dev/null: %m"); + log_error_errno(r, "Failed to apply local time delta, ignoring: %m"); + else + log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min); + + } else if (!in_initrd()) { + /* + * Do a dummy very first call to seal the kernel's time warp magic. + * + * Do not call this from inside the initrd. The initrd might not carry /etc/adjtime with LOCAL, but the + * real system could be set up that way. In such case, we need to delay the time-warp or the sealing + * until we reach the real system. + * + * Do no set the kernel's timezone. The concept of local time cannot be supported reliably, the time + * will jump or be incorrect at every daylight saving time change. All kernel local time concepts will + * be treated as UTC that way. + */ + (void) clock_reset_timewarp(); } - - r = clock_apply_epoch(); - if (r < 0) - log_error_errno(r, "Current system time is before build time, but cannot correct: %m"); - else if (r > 0) - log_info("System time before build time, advancing clock."); + } - r = initialize_join_controllers(); - if (r < 0) { - error_message = "Failed to initialize cgroup controllers"; - goto finish; - } + static void initialize_coredump(bool skip_setup) { - /* Mount /proc, /sys and friends, so that /proc/cmdline and - * /proc/$PID/fd is available. */ - if (getpid_cached() == 1) { + if (getpid_cached() != 1) + return; - /* Load the kernel modules early, so that we kdbus.ko is loaded before kdbusfs shall be mounted */ - if (!skip_setup) - kmod_setup(); + /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit) + * will process core dumps for system services by default. */ + if (setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0) + log_warning_errno(errno, "Failed to set RLIMIT_CORE: %m"); - r = mount_setup(loaded_policy); - if (r < 0) { - error_message = "Failed to mount API filesystems"; - goto finish; - } - } + /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored + * until the systemd-coredump tool is enabled via sysctl. */ + if (!skip_setup) + (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + } - /* Reset all signal handlers. */ - (void) reset_all_signal_handlers(); - (void) ignore_signals(SIGNALS_IGNORE, -1); + static void do_reexecute( + int argc, + char *argv[], + const struct rlimit *saved_rlimit_nofile, + const struct rlimit *saved_rlimit_memlock, + FDSet *fds, + const char *switch_root_dir, + const char *switch_root_init, + const char **ret_error_message) { + + unsigned i, j, args_size; + const char **args; + int r; - arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U); + assert(saved_rlimit_nofile); + assert(saved_rlimit_memlock); + assert(ret_error_message); - if (parse_config_file() < 0) { - error_message = "Failed to parse config file"; - goto finish; - } + /* Close and disarm the watchdog, so that the new instance can reinitialize it, but doesn't get rebooted while + * we do that */ + watchdog_close(true); - if (arg_system) { - r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); + /* Reset the RLIMIT_NOFILE to the kernel default, so that the new systemd can pass the kernel default to its + * child processes */ + + if (saved_rlimit_nofile->rlim_cur > 0) + (void) setrlimit(RLIMIT_NOFILE, saved_rlimit_nofile); + if (saved_rlimit_memlock->rlim_cur != (rlim_t) -1) + (void) setrlimit(RLIMIT_MEMLOCK, saved_rlimit_memlock); + + if (switch_root_dir) { + /* Kill all remaining processes from the initrd, but don't wait for them, so that we can handle the + * SIGCHLD for them after deserializing. */ + broadcast_signal(SIGTERM, false, true); + + /* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */ + r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE); if (r < 0) - log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); + log_error_errno(r, "Failed to switch root, trying to continue: %m"); } - /* Note that this also parses bits from the kernel command - * line, including "debug". */ - log_parse_environment(); + args_size = MAX(6, argc+1); + args = newa(const char*, args_size); - if (parse_argv(argc, argv) < 0) { - error_message = "Failed to parse commandline arguments"; - goto finish; - } + if (!switch_root_init) { + char sfd[DECIMAL_STR_MAX(int) + 1]; - /* Initialize default unit */ - if (!arg_default_unit) { - arg_default_unit = strdup(SPECIAL_DEFAULT_TARGET); - if (!arg_default_unit) { - r = log_oom(); - error_message = "Failed to set default unit"; - goto finish; - } - } + /* First try to spawn ourselves with the right path, and with full serialization. We do this only if + * the user didn't specify an explicit init to spawn. */ - if (arg_action == ACTION_TEST && - geteuid() == 0) { - log_error("Don't run test mode as root."); - goto finish; - } + assert(arg_serialization); + assert(fds); - if (!arg_system && - arg_action == ACTION_RUN && - sd_booted() <= 0) { - log_error("Trying to run as user instance, but the system has not been booted with systemd."); - goto finish; - } + xsprintf(sfd, "%i", fileno(arg_serialization)); - if (arg_system && - arg_action == ACTION_RUN && - running_in_chroot() > 0) { - log_error("Cannot be run in a chroot() environment."); - goto finish; + i = 0; + args[i++] = SYSTEMD_BINARY_PATH; + if (switch_root_dir) + args[i++] = "--switched-root"; + args[i++] = arg_system ? "--system" : "--user"; + args[i++] = "--deserialize"; + args[i++] = sfd; + args[i++] = NULL; + + assert(i <= args_size); + + /* + * We want valgrind to print its memory usage summary before reexecution. Valgrind won't do this is on + * its own on exec(), but it will do it on exit(). Hence, to ensure we get a summary here, fork() off + * a child, let it exit() cleanly, so that it prints the summary, and wait() for it in the parent, + * before proceeding into the exec(). + */ + valgrind_summary_hack(); + + (void) execv(args[0], (char* const*) args); + log_debug_errno(errno, "Failed to execute our own binary, trying fallback: %m"); + } + + /* Try the fallback, if there is any, without any serialization. We pass the original argv[] and envp[]. (Well, + * modulo the ordering changes due to getopt() in argv[], and some cleanups in envp[], but let's hope that + * doesn't matter.) */ + + arg_serialization = safe_fclose(arg_serialization); + fds = fdset_free(fds); + + /* Reopen the console */ + (void) make_console_stdio(); + + for (j = 1, i = 1; j < (unsigned) argc; j++) + args[i++] = argv[j]; + args[i++] = NULL; + assert(i <= args_size); + + /* Reenable any blocked signals, especially important if we switch from initial ramdisk to init=... */ + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); + + if (switch_root_init) { + args[0] = switch_root_init; + (void) execv(args[0], (char* const*) args); + log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m"); + } + + args[0] = "/sbin/init"; + (void) execv(args[0], (char* const*) args); + r = -errno; + + manager_status_printf(NULL, STATUS_TYPE_EMERGENCY, + ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL, + "Failed to execute /sbin/init"); + + if (r == -ENOENT) { + log_warning("No /sbin/init, trying fallback"); + + args[0] = "/bin/sh"; + args[1] = NULL; + (void) execv(args[0], (char* const*) args); + log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); + } else + log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m"); + + *ret_error_message = "Failed to execute fallback shell"; + } + + static int invoke_main_loop( + Manager *m, + bool *ret_reexecute, + int *ret_retval, /* Return parameters relevant for shutting down */ + const char **ret_shutdown_verb, /* … */ + FDSet **ret_fds, /* Return parameters for reexecuting */ + char **ret_switch_root_dir, /* … */ + char **ret_switch_root_init, /* … */ + const char **ret_error_message) { + + int r; + + assert(m); + assert(ret_reexecute); + assert(ret_retval); + assert(ret_shutdown_verb); + assert(ret_fds); + assert(ret_switch_root_dir); + assert(ret_switch_root_init); + assert(ret_error_message); + + for (;;) { + r = manager_loop(m); + if (r < 0) { + *ret_error_message = "Failed to run main loop"; + return log_emergency_errno(r, "Failed to run main loop: %m"); + } + + switch (m->exit_code) { + + case MANAGER_RELOAD: + log_info("Reloading."); + + r = parse_config_file(); + if (r < 0) + log_warning_errno(r, "Failed to parse config file, ignoring: %m"); + + set_manager_defaults(m); + + r = manager_reload(m); + if (r < 0) + log_warning_errno(r, "Failed to reload, ignoring: %m"); + + break; + + case MANAGER_REEXECUTE: + + r = prepare_reexecute(m, &arg_serialization, ret_fds, false); + if (r < 0) { + *ret_error_message = "Failed to prepare for reexecution"; + return r; + } + + log_notice("Reexecuting."); + + *ret_reexecute = true; + *ret_retval = EXIT_SUCCESS; + *ret_shutdown_verb = NULL; + *ret_switch_root_dir = *ret_switch_root_init = NULL; + + return 0; + + case MANAGER_SWITCH_ROOT: + if (!m->switch_root_init) { + r = prepare_reexecute(m, &arg_serialization, ret_fds, true); + if (r < 0) { + *ret_error_message = "Failed to prepare for reexecution"; + return r; + } + } else + *ret_fds = NULL; + + log_notice("Switching root."); + + *ret_reexecute = true; + *ret_retval = EXIT_SUCCESS; + *ret_shutdown_verb = NULL; + + /* Steal the switch root parameters */ + *ret_switch_root_dir = m->switch_root; + *ret_switch_root_init = m->switch_root_init; + m->switch_root = m->switch_root_init = NULL; + + return 0; + + case MANAGER_EXIT: + + if (MANAGER_IS_USER(m)) { + log_debug("Exit."); + + *ret_reexecute = false; + *ret_retval = m->return_value; + *ret_shutdown_verb = NULL; + *ret_fds = NULL; + *ret_switch_root_dir = *ret_switch_root_init = NULL; + + return 0; + } + + _fallthrough_; + case MANAGER_REBOOT: + case MANAGER_POWEROFF: + case MANAGER_HALT: + case MANAGER_KEXEC: { + static const char * const table[_MANAGER_EXIT_CODE_MAX] = { + [MANAGER_EXIT] = "exit", + [MANAGER_REBOOT] = "reboot", + [MANAGER_POWEROFF] = "poweroff", + [MANAGER_HALT] = "halt", + [MANAGER_KEXEC] = "kexec" + }; + + log_notice("Shutting down."); + + *ret_reexecute = false; + *ret_retval = m->return_value; + assert_se(*ret_shutdown_verb = table[m->exit_code]); + *ret_fds = NULL; + *ret_switch_root_dir = *ret_switch_root_init = NULL; + + return 0; + } + + default: + assert_not_reached("Unknown exit code."); + } + } + } + + static void log_execution_mode(bool *ret_first_boot) { + assert(ret_first_boot); + + if (arg_system) { + int v; + + log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")", + arg_action == ACTION_TEST ? "test " : "" ); + + v = detect_virtualization(); + if (v > 0) + log_info("Detected virtualization %s.", virtualization_to_string(v)); + + log_info("Detected architecture %s.", architecture_to_string(uname_architecture())); + + if (in_initrd()) { + *ret_first_boot = false; + log_info("Running in initial RAM disk."); + } else { + /* Let's check whether we are in first boot, i.e. whether /etc is still unpopulated. We use + * /etc/machine-id as flag file, for this: if it exists we assume /etc is populated, if it + * doesn't it's unpopulated. This allows container managers and installers to provision a + * couple of files already. If the container manager wants to provision the machine ID itself + * it should pass $container_uuid to PID 1. */ + + *ret_first_boot = access("/etc/machine-id", F_OK) < 0; + if (*ret_first_boot) + log_info("Running with unpopulated /etc."); + } + } else { + _cleanup_free_ char *t; + + t = uid_to_name(getuid()); + log_debug(PACKAGE_STRING " running in %suser mode for user " UID_FMT "/%s. (" SYSTEMD_FEATURES ")", + arg_action == ACTION_TEST ? " test" : "", getuid(), strna(t)); + + *ret_first_boot = false; + } + } + + static int initialize_runtime( + bool skip_setup, + struct rlimit *saved_rlimit_nofile, + struct rlimit *saved_rlimit_memlock, + const char **ret_error_message) { + + int r; + + assert(ret_error_message); + + /* Sets up various runtime parameters. Many of these initializations are conditionalized: + * + * - Some only apply to --system instances + * - Some only apply to --user instances + * - Some only apply when we first start up, but not when we reexecute + */ + + if (arg_system && !skip_setup) { + if (arg_show_status > 0) + status_welcome(); + + hostname_setup(); + machine_id_setup(NULL, arg_machine_id, NULL); + loopback_setup(); + bump_unix_max_dgram_qlen(); + test_usr(); + write_container_id(); + } + + if (arg_system && arg_watchdog_device) { + r = watchdog_set_device(arg_watchdog_device); + if (r < 0) + log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", + arg_watchdog_device); + } + + if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY) + watchdog_set_timeout(&arg_runtime_watchdog); + + if (arg_timer_slack_nsec != NSEC_INFINITY) + if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) + log_error_errno(errno, "Failed to adjust timer slack: %m"); + + if (arg_system && !cap_test_all(arg_capability_bounding_set)) { + r = capability_bounding_set_drop_usermode(arg_capability_bounding_set); + if (r < 0) { + *ret_error_message = "Failed to drop capability bounding set of usermode helpers"; + return log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m"); + } + + r = capability_bounding_set_drop(arg_capability_bounding_set, true); + if (r < 0) { + *ret_error_message = "Failed to drop capability bounding set"; + return log_emergency_errno(r, "Failed to drop capability bounding set: %m"); + } + } + + if (arg_syscall_archs) { + r = enforce_syscall_archs(arg_syscall_archs); + if (r < 0) { + *ret_error_message = "Failed to set syscall architectures"; + return r; + } + } + + if (!arg_system) + /* Become reaper of our children */ + if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) + log_warning_errno(errno, "Failed to make us a subreaper: %m"); + + if (arg_system) { + /* Bump up RLIMIT_NOFILE for systemd itself */ + (void) bump_rlimit_nofile(saved_rlimit_nofile); + (void) bump_rlimit_memlock(saved_rlimit_memlock); + } + + return 0; + } + + static int do_queue_default_job( + Manager *m, + const char **ret_error_message) { + + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + Job *default_unit_job; + Unit *target = NULL; + int r; + + log_debug("Activating default unit: %s", arg_default_unit); + + r = manager_load_unit(m, arg_default_unit, NULL, &error, &target); + if (r < 0) + log_error("Failed to load default target: %s", bus_error_message(&error, r)); + else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND)) + log_error_errno(target->load_error, "Failed to load default target: %m"); + else if (target->load_state == UNIT_MASKED) + log_error("Default target masked."); + + if (!target || target->load_state != UNIT_LOADED) { + log_info("Trying to load rescue target..."); + + r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target); + if (r < 0) { + *ret_error_message = "Failed to load rescue target"; + return log_emergency_errno(r, "Failed to load rescue target: %s", bus_error_message(&error, r)); + } else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND)) { + *ret_error_message = "Failed to load rescue target"; + return log_emergency_errno(target->load_error, "Failed to load rescue target: %m"); + } else if (target->load_state == UNIT_MASKED) { + *ret_error_message = "Rescue target masked"; + log_emergency("Rescue target masked."); + return -ERFKILL; + } + } + + assert(target->load_state == UNIT_LOADED); + + r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job); + if (r == -EPERM) { + log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r)); + + sd_bus_error_free(&error); + + r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job); + if (r < 0) { + *ret_error_message = "Failed to start default target"; + return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r)); + } + + } else if (r < 0) { + *ret_error_message = "Failed to isolate default target"; + return log_emergency_errno(r, "Failed to isolate default target: %s", bus_error_message(&error, r)); + } + + m->default_unit_job_id = default_unit_job->id; + + return 0; + } + + static void free_arguments(void) { + size_t j; + + /* Frees all arg_* variables, with the exception of arg_serialization */ + + for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) + arg_default_rlimit[j] = mfree(arg_default_rlimit[j]); + + arg_default_unit = mfree(arg_default_unit); + arg_confirm_spawn = mfree(arg_confirm_spawn); + arg_join_controllers = strv_free_free(arg_join_controllers); + arg_default_environment = strv_free(arg_default_environment); + arg_syscall_archs = set_free(arg_syscall_archs); + } + + int main(int argc, char *argv[]) { + Manager *m = NULL; + int r, retval = EXIT_FAILURE; + usec_t before_startup, after_startup; + char timespan[FORMAT_TIMESPAN_MAX]; + FDSet *fds = NULL; + bool reexecute = false; + const char *shutdown_verb = NULL; + dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL; + dual_timestamp userspace_timestamp = DUAL_TIMESTAMP_NULL; + dual_timestamp kernel_timestamp = DUAL_TIMESTAMP_NULL; + dual_timestamp security_start_timestamp = DUAL_TIMESTAMP_NULL; + dual_timestamp security_finish_timestamp = DUAL_TIMESTAMP_NULL; + static char systemd[] = "systemd"; + bool skip_setup = false; + bool loaded_policy = false; + bool queue_default_job = false; + bool first_boot = false; + char *switch_root_dir = NULL, *switch_root_init = NULL; + struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), saved_rlimit_memlock = RLIMIT_MAKE_CONST((rlim_t) -1); + const char *error_message = NULL; + + redirect_telinit(argc, argv); + + dual_timestamp_from_monotonic(&kernel_timestamp, 0); + dual_timestamp_get(&userspace_timestamp); + + /* Determine if this is a reexecution or normal bootup. We do + * the full command line parsing much later, so let's just + * have a quick peek here. */ + if (strv_find(argv+1, "--deserialize")) + skip_setup = true; + + /* If we have switched root, do all the special setup + * things */ + if (strv_find(argv+1, "--switched-root")) + skip_setup = false; + + /* If we get started via the /sbin/init symlink then we are + called 'init'. After a subsequent reexecution we are then + called 'systemd'. That is confusing, hence let's call us + systemd right-away. */ + program_invocation_short_name = systemd; + (void) prctl(PR_SET_NAME, systemd); + + saved_argv = argv; + saved_argc = argc; + + log_set_upgrade_syslog_to_journal(true); + + if (getpid_cached() == 1) { + /* Disable the umask logic */ + umask(0); + + /* Always reopen /dev/console when running as PID 1 or one of its pre-execve() children. This is + * important so that we never end up logging to any foreign stderr, for example if we have to log in a + * child process right before execve()'ing the actual binary, at a point in time where socket + * activation stderr/stdout area already set up. */ + log_set_always_reopen_console(true); + } + + if (getpid_cached() == 1 && detect_container() <= 0) { + + /* Running outside of a container as PID 1 */ + arg_system = true; + log_set_target(LOG_TARGET_KMSG); + log_open(); + + if (in_initrd()) + initrd_timestamp = userspace_timestamp; + + if (!skip_setup) { + r = mount_setup_early(); + if (r < 0) { + error_message = "Failed to mount early API filesystems"; + goto finish; + } + + dual_timestamp_get(&security_start_timestamp); + if (mac_selinux_setup(&loaded_policy) < 0) { + error_message = "Failed to load SELinux policy"; + goto finish; + } else if (mac_smack_setup(&loaded_policy) < 0) { + error_message = "Failed to load SMACK policy"; + goto finish; + } else if (ima_setup() < 0) { + error_message = "Failed to load IMA policy"; + goto finish; + } + dual_timestamp_get(&security_finish_timestamp); + } + + if (mac_selinux_init() < 0) { + error_message = "Failed to initialize SELinux policy"; + goto finish; + } + + if (!skip_setup) + initialize_clock(); + + /* Set the default for later on, but don't actually + * open the logs like this for now. Note that if we + * are transitioning from the initrd there might still + * be journal fd open, and we shouldn't attempt + * opening that before we parsed /proc/cmdline which + * might redirect output elsewhere. */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + + } else if (getpid_cached() == 1) { + /* Running inside a container, as PID 1 */ + arg_system = true; + log_set_target(LOG_TARGET_CONSOLE); + log_close_console(); /* force reopen of /dev/console */ + log_open(); + + /* For later on, see above... */ + log_set_target(LOG_TARGET_JOURNAL); + + /* clear the kernel timestamp, + * because we are in a container */ + kernel_timestamp = DUAL_TIMESTAMP_NULL; + } else { + /* Running as user instance */ + arg_system = false; + log_set_target(LOG_TARGET_AUTO); + log_open(); + + /* clear the kernel timestamp, + * because we are not PID 1 */ + kernel_timestamp = DUAL_TIMESTAMP_NULL; + } + + initialize_coredump(skip_setup); + + if (arg_system) { + if (fixup_environment() < 0) { + error_message = "Failed to fix up PID1 environment"; + goto finish; + } + + /* Try to figure out if we can use colors with the console. No + * need to do that for user instances since they never log + * into the console. */ + log_show_color(colors_enabled()); + r = make_null_stdio(); + if (r < 0) + log_warning_errno(r, "Failed to redirect standard streams to /dev/null: %m"); + } + + r = initialize_join_controllers(); + if (r < 0) { + error_message = "Failed to initialize cgroup controllers"; + goto finish; + } + + /* Mount /proc, /sys and friends, so that /proc/cmdline and + * /proc/$PID/fd is available. */ + if (getpid_cached() == 1) { + + /* Load the kernel modules early. */ + if (!skip_setup) + kmod_setup(); + + r = mount_setup(loaded_policy); + if (r < 0) { + error_message = "Failed to mount API filesystems"; + goto finish; + } + } + + /* Reset all signal handlers. */ + (void) reset_all_signal_handlers(); + (void) ignore_signals(SIGNALS_IGNORE, -1); + + arg_default_tasks_max = system_tasks_max_scale(DEFAULT_TASKS_MAX_PERCENTAGE, 100U); + + if (parse_config_file() < 0) { + error_message = "Failed to parse config file"; + goto finish; + } + + if (arg_system) { + r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0); + if (r < 0) + log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); + } + + /* Note that this also parses bits from the kernel command + * line, including "debug". */ + log_parse_environment(); + + if (parse_argv(argc, argv) < 0) { + error_message = "Failed to parse commandline arguments"; + goto finish; + } + + /* Initialize default unit */ + if (!arg_default_unit) { + arg_default_unit = strdup(SPECIAL_DEFAULT_TARGET); + if (!arg_default_unit) { + r = log_oom(); + error_message = "Failed to set default unit"; + goto finish; + } + } + + if (arg_action == ACTION_TEST && + geteuid() == 0) { + log_error("Don't run test mode as root."); + goto finish; + } + + if (!arg_system && + arg_action == ACTION_RUN && + sd_booted() <= 0) { + log_error("Trying to run as user instance, but the system has not been booted with systemd."); + goto finish; + } + + if (arg_system && + arg_action == ACTION_RUN && + running_in_chroot() > 0) { + log_error("Cannot be run in a chroot() environment."); + goto finish; } if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP)) { diff --cc src/core/manager.c index 7ae7a4b,81c4d52..7d6cb19 --- a/src/core/manager.c +++ b/src/core/manager.c @@@ -724,6 -737,19 +737,19 @@@ int manager_new(UnitFileScope scope, un if (r < 0) goto fail; + if (MANAGER_IS_SYSTEM(m) && test_run_flags == 0) { + r = mkdir_label("/run/systemd/units", 0755); + if (r < 0 && r != -EEXIST) + goto fail; + } + + m->taint_usr = + !in_initrd() && + dir_is_empty("/usr") > 0; + - /* Note that we do not set up the notify fd here. We do that after deserialization, ++ /* Note that we do not set up neither kdbus, nor the notify fd here. We do that after deserialization, + * since they might have gotten serialized across the reexec. */ + *_m = m; return 0; @@@ -957,10 -961,9 +983,10 @@@ static int manager_connect_bus(Manager u = manager_get_unit(m, SPECIAL_DBUS_SERVICE); try_bus_connect = - (u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) && - (reexecuting || - (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"))); + (m->kdbus_fd >= 0) || - ((u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) && ++ ((u && SERVICE(u)->deserialized_state == SERVICE_RUNNING) && + (reexecuting || + (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS")))); /* Try to connect to the buses, if possible. */ return bus_init(m, try_bus_connect); @@@ -1400,25 -1400,22 +1424,28 @@@ int manager_startup(Manager *m, FILE *s /* We might have deserialized the notify fd, but if we didn't * then let's create the bus now */ - q = manager_setup_notify(m); - if (q < 0 && r == 0) - r = q; + r = manager_setup_notify(m); + if (r < 0) + /* No sense to continue without notifications, our children would fail anyway. */ + return r; - q = manager_setup_cgroups_agent(m); - if (q < 0 && r == 0) - r = q; + r = manager_setup_cgroups_agent(m); + if (r < 0) + /* Likewise, no sense to continue without empty cgroup notifications. */ + return r; + /* We might have deserialized the kdbus control fd, but if we + * didn't, then let's create the bus now. */ + manager_setup_kdbus(m); + manager_connect_bus(m, !!serialization); + (void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed); + - q = manager_setup_user_lookup_fd(m); - if (q < 0 && r == 0) - r = q; + r = manager_setup_user_lookup_fd(m); + if (r < 0) + /* This shouldn't fail, except if things are really broken. */ + return r; - /* Let's connect to the bus now. */ + /* We might have deserialized the kdbus control fd, but if we didn't, then let's create the bus now. */ (void) manager_connect_bus(m, !!serialization); (void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed); @@@ -2870,9 -2868,24 +2918,24 @@@ int manager_deserialize(Manager *m, FIL if (strv_extend(&m->deserialized_subscribed, val) < 0) log_oom(); + } else { + ManagerTimestamp q; - } else - log_debug("Unknown serialization item '%s'", l); + for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) { + val = startswith(l, manager_timestamp_to_string(q)); + if (!val) + continue; + + val = startswith(val, "-timestamp="); + if (val) + break; + } + + if (q < _MANAGER_TIMESTAMP_MAX) /* found it */ + dual_timestamp_deserialize(val, m->timestamps + q); - else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */ ++ else + log_notice("Unknown serialization item '%s'", l); + } } for (;;) { diff --cc src/core/mount-setup.c index 9819082,7171d8f..3fc8cb3 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@@ -91,24 -93,21 +94,24 @@@ static const MountPoint mount_table[] { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, NULL, MNT_IN_CONTAINER }, #if ENABLE_SMACK - { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME, - mac_smack_use, MNT_FATAL }, -#endif - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, + { "tmpfs", "/run", "tmpfs", "mode=755,smackfstransmute=System::Run", MS_NOSUID|MS_NODEV|MS_STRICTATIME|MS_NOEXEC, + mac_smack_use, MNT_FATAL }, + { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, + mac_smack_use, MNT_IN_CONTAINER }, +#else + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME|MS_NOEXEC, NULL, MNT_FATAL|MNT_IN_CONTAINER }, + { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, + cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, +#endif { "cgroup", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_unified_wanted, MNT_IN_CONTAINER }, + cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE }, { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_unified_wanted, MNT_IN_CONTAINER }, + cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE }, - { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, - cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER }, { "cgroup", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_hybrid_wanted, MNT_IN_CONTAINER }, + cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE }, { "cgroup", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, - cg_is_hybrid_wanted, MNT_IN_CONTAINER }, + cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE }, { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV, cg_is_legacy_wanted, MNT_IN_CONTAINER }, { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, diff --cc src/core/service.c index 5277fab,ef1be33..9bad177 --- a/src/core/service.c +++ b/src/core/service.c @@@ -615,23 -671,12 +674,23 @@@ static int service_setup_bus_name(Servi if (!s->bus_name) return 0; - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); + if (is_kdbus_available()) { + const char *n; + + n = strjoina(s->bus_name, ".busname"); - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); ++ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true, UNIT_DEPENDENCY_FILE); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m"); + + } else { + /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); ++ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); + } - /* We always want to be ordered against dbus.socket if both are in the transaction. */ + /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */ - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true); + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true, UNIT_DEPENDENCY_FILE); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); @@@ -3440,15 -3410,14 +3469,16 @@@ static void service_notify_message Service *s = SERVICE(u); bool notify_dbus = false; const char *e; + char **i; + int r; assert(u); + assert(ucred); - if (!service_notify_message_authorized(SERVICE(u), pid, tags, fds)) + if (!service_notify_message_authorized(SERVICE(u), ucred->pid, tags, fds)) return; - if (log_get_max_level() >= LOG_DEBUG) { + if (s->notify_access == NOTIFY_NONE) { _cleanup_free_ char *cc = NULL; cc = strv_join(tags, ", "); diff --cc src/core/unit.h index cbcd1b0,fdd8231..9cf209d --- a/src/core/unit.h +++ b/src/core/unit.h @@@ -295,14 -372,28 +372,29 @@@ struct UnitStatusMessageFormats const char *finished_stop_job[_JOB_RESULT_MAX]; }; - typedef enum UnitSetPropertiesMode { - UNIT_CHECK = 0, - UNIT_RUNTIME = 1, - UNIT_PERSISTENT = 2, - } UnitSetPropertiesMode; + /* Flags used when writing drop-in files or transient unit files */ + typedef enum UnitWriteFlags { + /* Write a runtime unit file or drop-in (i.e. one below /run) */ + UNIT_RUNTIME = 1 << 0, + + /* Write a persistent drop-in (i.e. one below /etc) */ + UNIT_PERSISTENT = 1 << 1, + + /* Place this item in the per-unit-type private section, instead of [Unit] */ + UNIT_PRIVATE = 1 << 2, + + /* Apply specifier escaping before writing */ + UNIT_ESCAPE_SPECIFIERS = 1 << 3, + + /* Apply C escaping before writing */ + UNIT_ESCAPE_C = 1 << 4, + } UnitWriteFlags; + + /* Returns true if neither persistent, nor runtime storage is requested, i.e. this is a check invocation only */ + #define UNIT_WRITE_FLAGS_NOOP(flags) (((flags) & (UNIT_RUNTIME|UNIT_PERSISTENT)) == 0) #include "automount.h" +#include "busname.h" #include "device.h" #include "path.h" #include "scope.h" diff --cc src/dbus1-generator/dbus1-generator.c index e9386a7,0000000..a1eb37d mode 100755,000000..100755 --- a/src/dbus1-generator/dbus1-generator.c +++ b/src/dbus1-generator/dbus1-generator.c @@@ -1,363 -1,0 +1,363 @@@ +/*** + This file is part of systemd. + + Copyright 2013 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 "alloc-util.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "conf-parser.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "mkdir.h" +#include "special.h" +#include "unit-name.h" +#include "util.h" + +static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; + +static int create_dbus_files( + const char *path, + const char *name, + const char *service, + const char *exec, + const char *user, + const char *type) { + + _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(path); + assert(name); + assert(service || exec); + + if (!service) { + _cleanup_free_ char *a = NULL; + + s = strjoin("dbus-", name, ".service", NULL); + if (!s) + return log_oom(); + + a = strjoin(arg_dest_late, "/", s, NULL); + if (!a) + return log_oom(); + + f = fopen(a, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create %s: %m", a); + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n" + "Description=DBUS1: %s\n" + "Documentation=man:systemd-dbus1-generator(8)\n\n" + "[Service]\n" + "ExecStart=%s\n" + "Type=dbus\n" + "BusName=%s\n", + path, + name, + exec, + name); + + if (user) + fprintf(f, "User=%s\n", user); + + + if (type) { + fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type); + + if (streq(type, "system")) + fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n"); + else if (streq(type, "session")) { + char *run; + + run = getenv("XDG_RUNTIME_DIR"); + if (!run) { + log_error("XDG_RUNTIME_DIR not set."); + return -EINVAL; + } + + fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n", + getuid(), run); + } + } + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write %s: %m", a); + + f = safe_fclose(f); + + service = s; + } + + b = strjoin(arg_dest_late, "/", name, ".busname", NULL); + if (!b) + return log_oom(); + + f = fopen(b, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create %s: %m", b); + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "SourcePath=%s\n" + "Description=DBUS1: %s\n" + "Documentation=man:systemd-dbus1-generator(8)\n\n" + "[BusName]\n" + "Name=%s\n" + "Service=%s\n" + "AllowWorld=talk\n", + path, + name, + name, + service); + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write %s: %m", b); + + lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL); + if (!lnk) + return log_oom(); + + mkdir_parents_label(lnk, 0755); + if (symlink(b, lnk)) + return log_error_errno(errno, "Failed to create symlink %s: %m", lnk); + + return 0; +} + +static int add_dbus(const char *path, const char *fname, const char *type) { + _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL; + + const ConfigTableItem table[] = { + { "D-BUS Service", "Name", config_parse_string, 0, &name }, + { "D-BUS Service", "Exec", config_parse_string, 0, &exec }, + { "D-BUS Service", "User", config_parse_string, 0, &user }, + { "D-BUS Service", "SystemdService", config_parse_string, 0, &service }, + { }, + }; + + char *p; + int r; + + assert(path); + assert(fname); + + p = strjoina(path, "/", fname); + r = config_parse(NULL, p, NULL, + "D-BUS Service\0", + config_item_table_lookup, table, - true, false, true, NULL); ++ CONFIG_PARSE_RELAXED|CONFIG_PARSE_WARN, NULL); + if (r < 0) + return r; + + if (!name) { + log_warning("Activation file %s lacks name setting, ignoring.", p); + return 0; + } + + if (!service_name_is_valid(name)) { + log_warning("Bus service name %s is not valid, ignoring.", name); + return 0; + } + + if (streq(name, "org.freedesktop.systemd1")) { + log_debug("Skipping %s, identified as systemd.", p); + return 0; + } + + if (service) { + if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) { + log_warning("Unit name %s is not valid, ignoring.", service); + return 0; + } + if (!endswith(service, ".service")) { + log_warning("Bus names can only activate services, ignoring %s.", p); + return 0; + } + } else { + if (!exec || streq(exec, "/bin/false")) { + log_warning("Neither service name nor binary path specified, ignoring %s.", p); + return 0; + } + + if (exec[0] != '/') { + log_warning("Exec= in %s does not start with an absolute path, ignoring.", p); + return 0; + } + } + + return create_dbus_files(p, name, service, exec, user, type); +} + +static int parse_dbus_fragments(const char *path, const char *type) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r; + + assert(path); + assert(type); + + d = opendir(path); + if (!d) { + if (errno == -ENOENT) + return 0; + + return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); + } + + r = 0; + FOREACH_DIRENT(de, d, goto fail) { + int q; + + if (!endswith(de->d_name, ".service")) + continue; + + q = add_dbus(path, de->d_name, type); + if (q < 0) + r = q; + } + + return r; + +fail: + return log_error_errno(errno, "Failed to read D-Bus services directory: %m"); +} + +static int link_busnames_target(const char *units) { + const char *f, *t; + + f = strjoina(units, "/" SPECIAL_BUSNAMES_TARGET); + t = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET); + + mkdir_parents_label(t, 0755); + if (symlink(f, t) < 0) + return log_error_errno(errno, "Failed to create symlink %s: %m", t); + + return 0; +} + +static int create_compatibility(const char *units, const char *type) { + const char *t; + _cleanup_fclose_ FILE *f = NULL; + int r; + + t = strjoina(arg_dest, "/" SPECIAL_DBUS_SERVICE); + if (!t) + return log_oom(); + + f = fopen(t, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create %s: %m", t); + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "Description=DBUS1: dbus.service for kdbus compatibility\n" + "[Service]\n" + "ExecStart=/bin/true\n" + "RemainAfterExit=yes\n"); + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write %s: %m", t); + + f = safe_fclose(f); + + + t = strjoina(arg_dest, "/" SPECIAL_DBUS_SOCKET); + if (!t) + return log_oom(); + + f = fopen(t, "wxe"); + if (!f) + return log_error_errno(errno, "Failed to create %s: %m", t); + + fprintf(f, + "# Automatically generated by systemd-dbus1-generator\n\n" + "[Unit]\n" + "Description=DBUS1: dbus.socket for kdbus compatibility\n" + "[Socket]\n" + "SmackLabelIPIn=^\n" + "ListenStream=@/tmp/.kdbus_bus_%s_%d\n", type, getuid()); + + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write %s: %m", t); + + f = safe_fclose(f); + + return 0; +} + +int main(int argc, char *argv[]) { + const char *path, *type, *units; + int r, q; + + if (argc > 1 && argc != 4) { + log_error("This program takes three or no arguments."); + return EXIT_FAILURE; + } + + if (argc > 1) { + arg_dest = argv[1]; + arg_dest_late = argv[3]; + } + + log_set_target(LOG_TARGET_SAFE); + log_parse_environment(); + log_open(); + + umask(0022); + + if (!is_kdbus_available()) + return 0; + + r = cg_pid_get_owner_uid(0, NULL); + if (r >= 0) { + path = "/usr/share/dbus-1/services"; + type = "session"; + units = USER_DATA_UNIT_PATH; + } else if (r == -ENXIO) { + path = "/usr/share/dbus-1/system-services"; + type = "system"; + units = SYSTEM_DATA_UNIT_PATH; + } else + return log_error_errno(r, "Failed to determine whether we are running as user or system instance: %m"); + + r = parse_dbus_fragments(path, type); + + /* FIXME: One day this should just be pulled in statically from basic.target */ + q = link_busnames_target(units); + if (q < 0) + r = q; + + q = create_compatibility(units, type); + if (q < 0) + r = q; + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --cc src/libsystemd/sd-bus/test-bus-zero-copy.c index e599427,0000000..7f6d7f4 mode 100644,000000..100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@@ -1,210 -1,0 +1,210 @@@ +/*** + This file is part of systemd. + + Copyright 2013 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 + +#include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" +#include "bus-kernel.h" +#include "bus-message.h" +#include "fd-util.h" +#include "log.h" +#include "memfd-util.h" +#include "string-util.h" +#include "util.h" + +#define FIRST_ARRAY 17 +#define SECOND_ARRAY 33 + +#define STRING_SIZE 123 + +int main(int argc, char *argv[]) { + _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; + const char *unique; + uint8_t *p; + sd_bus *a, *b; + int r, bus_ref; + sd_bus_message *m; + int f; + uint64_t sz; + uint32_t u32; + size_t i, l; + char *s; + _cleanup_close_ int sfd = -1; + + log_set_max_level(LOG_DEBUG); + + assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid_cached()) >= 0); + + bus_ref = bus_kernel_create_bus(name, false, &bus_name); + if (bus_ref == -ENOENT) + return EXIT_TEST_SKIP; + + assert_se(bus_ref >= 0); + + address = strappend("kernel:path=", bus_name); + assert_se(address); + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_new(&b); + assert_se(r >= 0); + + r = sd_bus_set_address(a, address); + assert_se(r >= 0); + + r = sd_bus_set_address(b, address); + assert_se(r >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_start(b); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &unique); + assert_se(r >= 0); + + r = sd_bus_message_new_method_call(b, &m, unique, "/a/path", "an.inter.face", "AMethod"); + assert_se(r >= 0); + + r = sd_bus_message_open_container(m, 'r', "aysay"); + assert_se(r >= 0); + + r = sd_bus_message_append_array_space(m, 'y', FIRST_ARRAY, (void**) &p); + assert_se(r >= 0); + + p[0] = '<'; + memset(p+1, 'L', FIRST_ARRAY-2); + p[FIRST_ARRAY-1] = '>'; + + f = memfd_new_and_map(NULL, STRING_SIZE, (void**) &s); + assert_se(f >= 0); + + s[0] = '<'; + for (i = 1; i < STRING_SIZE-2; i++) + s[i] = '0' + (i % 10); + s[STRING_SIZE-2] = '>'; + s[STRING_SIZE-1] = 0; + munmap(s, STRING_SIZE); + + r = memfd_get_size(f, &sz); + assert_se(r >= 0); + assert_se(sz == STRING_SIZE); + + r = sd_bus_message_append_string_memfd(m, f, 0, (uint64_t) -1); + assert_se(r >= 0); + + close(f); + + f = memfd_new_and_map(NULL, SECOND_ARRAY, (void**) &p); + assert_se(f >= 0); + + p[0] = '<'; + memset(p+1, 'P', SECOND_ARRAY-2); + p[SECOND_ARRAY-1] = '>'; + munmap(p, SECOND_ARRAY); + + r = memfd_get_size(f, &sz); + assert_se(r >= 0); + assert_se(sz == SECOND_ARRAY); + + r = sd_bus_message_append_array_memfd(m, 'y', f, 0, (uint64_t) -1); + assert_se(r >= 0); + + close(f); + + r = sd_bus_message_close_container(m); + assert_se(r >= 0); + + r = sd_bus_message_append(m, "u", 4711); + assert_se(r >= 0); + + assert_se((sfd = memfd_new_and_map(NULL, 6, (void**) &p)) >= 0); + memcpy(p, "abcd\0", 6); + munmap(p, 6); + assert_se(sd_bus_message_append_string_memfd(m, sfd, 1, 4) >= 0); + - r = bus_message_seal(m, 55, 99*USEC_PER_SEC); ++ r = sd_bus_message_seal(m, 55, 99*USEC_PER_SEC); + assert_se(r >= 0); + + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); + + r = sd_bus_send(b, m, NULL); + assert_se(r >= 0); + + sd_bus_message_unref(m); + + r = sd_bus_process(a, &m); + assert_se(r > 0); + + bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER); + sd_bus_message_rewind(m, true); + + r = sd_bus_message_enter_container(m, 'r', "aysay"); + assert_se(r > 0); + + r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l); + assert_se(r > 0); + assert_se(l == FIRST_ARRAY); + + assert_se(p[0] == '<'); + for (i = 1; i < l-1; i++) + assert_se(p[i] == 'L'); + assert_se(p[l-1] == '>'); + + r = sd_bus_message_read(m, "s", &s); + assert_se(r > 0); + + assert_se(s[0] == '<'); + for (i = 1; i < STRING_SIZE-2; i++) + assert_se(s[i] == (char) ('0' + (i % 10))); + assert_se(s[STRING_SIZE-2] == '>'); + assert_se(s[STRING_SIZE-1] == 0); + + r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l); + assert_se(r > 0); + assert_se(l == SECOND_ARRAY); + + assert_se(p[0] == '<'); + for (i = 1; i < l-1; i++) + assert_se(p[i] == 'P'); + assert_se(p[l-1] == '>'); + + r = sd_bus_message_exit_container(m); + assert_se(r > 0); + + r = sd_bus_message_read(m, "u", &u32); + assert_se(r > 0); + assert_se(u32 == 4711); + + r = sd_bus_message_read(m, "s", &s); + assert_se(r > 0); + assert_se(streq_ptr(s, "bcd")); + + sd_bus_message_unref(m); + + sd_bus_unref(a); + sd_bus_unref(b); + + return 0; +} diff --cc src/login/logind-user.c index ddadd61,94e250b..f5e4799 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@@ -21,7 -22,7 +22,8 @@@ #include #include #include + #include +#include #include "alloc-util.h" #include "bus-common-errors.h" @@@ -330,38 -332,6 +333,38 @@@ int user_load(User *u) return r; } +static int user_mkdir_system_share_path(User *u) { + int r; + gid_t system_share_gid; + _cleanup_free_ char *t = NULL; + const char *system_share_group = "system_share"; + + r = get_group_creds(&system_share_group, &system_share_gid); + if (r < 0) + return r; + + /* mount option "gid=system_share" doesn't work. So, we have to modify gid here*/ + r = chmod_and_chown(u->runtime_path, 0750, u->uid, system_share_gid); + if (r < 0) + return log_error_errno(r, "Failed to change runtime directory ownership and mode: %m"); + + r = asprintf(&t, "/run/user/"UID_FMT"/system_share", u->uid); + if (r < 0) + return log_oom(); + - r = mkdir_safe_label(t, 0750, u->uid, system_share_gid); ++ r = mkdir_safe_label(t, 0750, u->uid, system_share_gid, false); + if (r < 0) + return log_error_errno(r, "Failed to create '%s': %m", t); + + if (mac_smack_use()) { + r = lsetxattr(t, "security.SMACK64", SMACK_STAR_LABEL, strlen(SMACK_STAR_LABEL), 0); + if (r < 0) + return log_error_errno(r, "Failed to apply smack label * to '%s': %m", t); + } + + return 0; +} + static int user_mkdir_runtime_path(User *u) { int r; diff --cc src/test/test-parse-util.c index 4e5cbd2,8259e13..b67f9aa --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@@ -431,46 -459,14 +459,52 @@@ static void test_safe_atoi16(void) r = safe_atoi16("123x", &l); assert_se(r == -EINVAL); + + r = safe_atoi16("12.3", &l); + assert_se(r == -EINVAL); + + r = safe_atoi16("", &l); + assert_se(r == -EINVAL); } +static void test_safe_atoux16(void) { + int r; + uint16_t l; + + r = safe_atoux16("1234", &l); + assert_se(r == 0); + assert_se(l == 0x1234); + + r = safe_atoux16("abcd", &l); + assert_se(r == 0); + assert_se(l == 0xabcd); + + r = safe_atoux16(" 1234", &l); + assert_se(r == 0); + assert_se(l == 0x1234); + + r = safe_atoux16("12345", &l); + assert_se(r == -ERANGE); + + r = safe_atoux16("-1", &l); + assert_se(r == -ERANGE); + + r = safe_atoux16(" -1", &l); + assert_se(r == -ERANGE); + + r = safe_atoux16("junk", &l); + assert_se(r == -EINVAL); + + r = safe_atoux16("123x", &l); + assert_se(r == -EINVAL); + + r = safe_atoux16("12.3", &l); + assert_se(r == -EINVAL); + + r = safe_atoux16("", &l); + assert_se(r == -EINVAL); +} + static void test_safe_atou64(void) { int r; uint64_t l; diff --cc test/meson.build index 37ad97b,5c533f4..183a889 --- a/test/meson.build +++ b/test/meson.build @@@ -1,18 -1,38 +1,45 @@@ + # SPDX-License-Identifier: LGPL-2.1+ + # + # Copyright 2017 Zbigniew Jędrzejewski-Szmek + # + # 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 . + test_data_files = ''' a.service - basic.target b.service + basic.target ++ bus-policy/hello.conf ++ bus-policy/methods.conf ++ bus-policy/ownerships.conf ++ bus-policy/signals.conf ++ bus-policy/check-own-rules.conf ++ bus-policy/many-rules.conf ++ bus-policy/test.conf c.service - daughter.service d.service - end.service + daughter.service e.service + end.service f.service - grandchild.service g.service + grandchild.service + h.service hello-after-sleep.target hello.service - h.service + hwdb/10-bad.hwdb + journal-data/journal-1.txt + journal-data/journal-2.txt parent-deep.slice parent.slice sched_idle_bad.service diff --cc test/test-functions index 50e0a16,a2f8272..5798fac --- a/test/test-functions +++ b/test/test-functions @@@ -20,7 -21,7 +21,7 @@@ if ! ROOTLIBDIR=$(pkg-config --variable ROOTLIBDIR=/usr/lib/systemd fi - BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm chmod chown ln" -BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false" ++BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm chmod chown ln true false" DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find" STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))" diff --cc units/meson.build index 1b38d91,814ee78..0a1d4d1 --- a/units/meson.build +++ b/units/meson.build @@@ -1,5 -1,23 +1,22 @@@ + # SPDX-License-Identifier: LGPL-2.1+ + # + # Copyright 2017 Zbigniew Jędrzejewski-Szmek + # + # 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 . + units = [ ['basic.target', ''], - ['bluetooth.target', ''], ['cryptsetup-pre.target', 'HAVE_LIBCRYPTSETUP'], ['cryptsetup.target', 'HAVE_LIBCRYPTSETUP', 'sysinit.target.wants/'], @@@ -211,18 -225,11 +227,18 @@@ in_units = 'multi-user.target.wants/ graphical.target.wants/ rescue.target.wants/'], ['systemd-update-utmp.service', 'ENABLE_UTMP', 'sysinit.target.wants/'], - ['systemd-user-sessions.service', '', + ['systemd-user-sessions.service', 'HAVE_PAM', 'multi-user.target.wants/'], - ['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE'], + ['systemd-vconsole-setup.service', 'ENABLE_VCONSOLE', + 'sysinit.target.wants/'], ['systemd-volatile-root.service', ''], ['user@.service', ''], + ['booting-done.service', '', + 'delayed.target.wants/'], + ['system-delayed-target-done.service', '', + 'delayed.target.wants/'], + ['system-default-target-done.service', '', 'graphical.target.wants/'], + ['system-delayed-target-trigger.service', '', 'graphical.target.wants/'], ] m4_units = [ diff --cc units/systemd-nspawn@.service.in index 80d4bc9,c3194d4..bfa3a6c --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@@ -19,9 -21,9 +21,10 @@@ KillMode=mixe Type=notify RestartForceExitStatus=133 SuccessExitStatus=133 + WatchdogSec=3min Slice=machine.slice Delegate=yes +SmackProcessLabel=System TasksMax=16384 # Enforce a strict device policy, similar to the one nspawn configures when it diff --cc units/systemd-tmpfiles-clean.service.in index deeca5f,d1025af..7c2a563 --- a/units/systemd-tmpfiles-clean.service.in +++ b/units/systemd-tmpfiles-clean.service.in @@@ -16,5 -18,5 +18,6 @@@ Before=shutdown.targe [Service] Type=oneshot ExecStart=@rootbindir@/systemd-tmpfiles --clean + SuccessExitStatus=65 IOSchedulingClass=idle +SmackProcessLabel=System::Privileged diff --cc units/systemd-tmpfiles-setup-dev.service.in index 561be7b,6a6ebed..594fe9a --- a/units/systemd-tmpfiles-setup-dev.service.in +++ b/units/systemd-tmpfiles-setup-dev.service.in @@@ -18,4 -20,4 +20,5 @@@ ConditionCapability=CAP_SYS_MODUL Type=oneshot RemainAfterExit=yes ExecStart=@rootbindir@/systemd-tmpfiles --prefix=/dev --create --boot + SuccessExitStatus=65 +SmackProcessLabel=System::Privileged diff --cc units/systemd-tmpfiles-setup.service.in index 7f77b82,0410d0b..f573e3c --- a/units/systemd-tmpfiles-setup.service.in +++ b/units/systemd-tmpfiles-setup.service.in @@@ -18,4 -20,4 +20,5 @@@ RefuseManualStop=ye Type=oneshot RemainAfterExit=yes ExecStart=@rootbindir@/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev + SuccessExitStatus=65 +SmackProcessLabel=System::Privileged diff --cc units/user/meson.build index 253d7bb,e463ae2..41d21e8 --- a/units/user/meson.build +++ b/units/user/meson.build @@@ -1,6 -1,23 +1,23 @@@ + # SPDX-License-Identifier: LGPL-2.1+ + # + # Copyright 2017 Zbigniew Jędrzejewski-Szmek + # + # 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 . + units = [ 'basic.target', - 'bluetooth.target', + 'busnames.target', 'default.target', 'exit.target', 'graphical-session-pre.target', @@@ -12,26 -29,18 +29,29 @@@ 'sockets.target', 'sound.target', 'timers.target', + 'systemd-tmpfiles-clean.timer', ] +units += [ + 'delayed.target', + 'user-delayed-target-trigger.service', + 'user-default-target-done.service', + 'user-delayed-target-done.service', +] + foreach file : units install_data(file, install_dir : userunitdir) endforeach +meson.add_install_script('../meson-add-wants.sh', userunitdir, 'default.target.wants/', 'user-delayed-target-trigger.service') +meson.add_install_script('../meson-add-wants.sh', userunitdir, 'default.target.wants/', 'user-default-target-done.service') +meson.add_install_script('../meson-add-wants.sh', userunitdir, 'delayed.target.wants/', 'user-delayed-target-done.service') + in_units = [ 'systemd-exit.service', + 'systemd-tmpfiles-clean.service', + 'systemd-tmpfiles-setup.service', ] foreach file : in_units diff --cc units/user@.service.in index 33f11e1,e8195ac..825cf63 --- a/units/user@.service.in +++ b/units/user@.service.in @@@ -11,18 -13,11 +13,18 @@@ After=systemd-user-sessions.servic [Service] User=%i +Group=users PAMName=systemd-user -Type=notify +Type=simple ExecStart=-@rootlibexecdir@/systemd --user +SmackProcessLabel=User Slice=user-%i.slice KillMode=mixed - Delegate=yes + Delegate=pids cpu TasksMax=infinity +Environment=DBUS_SESSION_BUS_ADDRESS=kernel:path=/sys/fs/kdbus/%i-user/bus;unix:path=/run/user/%i/bus +Environment=XDG_RUNTIME_DIR=/run/user/%i +Capabilities=cap_sys_admin,cap_mac_admin,cap_setgid,cap_dac_override=i +SecureBits=keep-caps +TimeoutStartSec=infinity TimeoutStopSec=120s