* sd-bus:
- EBADSLT handling
- GetAllProperties() on a non-existing object does not result in a failure currently
+ - kdbus: process fd=-1 for incoming msgs
- port to sd-resolve for connecting to TCP dbus servers
+ - kdbus: maybe add controlling tty metadata fields
- see if we can introduce a new sd_bus_get_owner_machine_id() call to retrieve the machine ID of the machine of the bus itself
+ - when kdbus does not take our message without memfds, try again with memfds
- see if we can drop more message validation on the sending side
- add API to clone sd_bus_message objects
- - make AddMatch calls on dbus1 transports async?
- - kdbus: matches against source or destination pids for an "strace -p"-like feel. Problem: The PID info needs to be available in userspace too...
- longer term: priority inheritance
- dbus spec updates:
+ - kdbus mapping
- NameLost/NameAcquired obsolete
- GVariant
- path escaping
substs.set(name, path)
endforeach
-if run_command('ln', '--relative', '--help').returncode() != 0
- error('ln does not support --relative')
-endif
+ conf.set_quoted('TELINIT', get_option('telinit-path'))
+
+#if run_command('ln', '--relative', '--help').returncode() != 0
+# error('ln does not support --relative')
+#endif
############################################################
['gnu-efi', have_gnu_efi],
['kmod'],
['xkbcommon'],
+ ['pcre2'],
['blkid'],
['dbus'],
+ ['kdbus'],
['glib'],
['nss-myhostname', conf.get('ENABLE_MYHOSTNAME') == 1],
['hwdb'],
--- /dev/null
- Version: 236
+# "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: 237
+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 <<EOF >> 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
"/usr/lib/kbd/keymaps/\0"
#endif
- #define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
+ /* Note that we use the new /run prefix here (instead of /var/run) since we require them to be aliases and that way we
+ * become independent of /var being mounted */
-#define DEFAULT_SYSTEM_BUS_ADDRESS "unix:path=/run/dbus/system_bus_socket"
-#define DEFAULT_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
++#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/run/dbus/system_bus_socket"
+#define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus"
+#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS
+#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
+#define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus"
++#define DEFAULT_USER_BUS_ADDRESS_FMT KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT
#define PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
* function what to do when encountering a symlink with an absolute path as directory: prefix it by the
* specified path. */
+ /* A root directory of "/" or "" is identical to none */
+ if (isempty(original_root) || path_equal(original_root, "/"))
+ original_root = NULL;
+
if (original_root) {
- r = path_make_absolute_cwd(original_root, &root);
- if (r < 0)
- return r;
+ int res = path_make_absolute_cwd(original_root, &root);
+ if (res != 0)
+ return res;
+ if (root == NULL)
+ return -ENOENT;
- if (flags & CHASE_PREFIX_ROOT)
+ if (flags & CHASE_PREFIX_ROOT) {
+
+ /* We don't support relative paths in combination with a root directory */
+ if (!path_is_absolute(path))
+ return -EINVAL;
+
path = prefix_roota(root, path);
+ }
}
- r = path_make_absolute_cwd(path, &buffer);
- if (r < 0)
- return r;
+ int res = path_make_absolute_cwd(path, &buffer);
+ if (res != 0)
+ return res;
+ if (buffer == NULL)
+ return -ENOENT;
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
if (fd < 0)
return -errno;
+ if (flags & CHASE_SAFE) {
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!safe_transition(&previous_stat, &st))
+ return -EPERM;
+
+ previous_stat = st;
+ }
+
free(done);
+ if (flags & CHASE_SAFE) {
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!safe_transition(&previous_stat, &st))
+ return -EPERM;
+
+ previous_stat = st;
+ }
+
/* Note that we do not revalidate the root, we take it as is. */
if (isempty(root))
done = NULL;
#define RTA_PREF 20
#endif
++#ifndef RTAX_QUICKACK
++#define RTAX_QUICKACK 15
++#endif
++
#ifndef IPV6_UNICAST_IF
#define IPV6_UNICAST_IF 76
#endif
return 0;
}
+int safe_atoux16(const char *s, uint16_t *ret) {
+ char *x = NULL;
+ unsigned long l;
+
+ assert(s);
+ assert(ret);
+
+ s += strspn(s, WHITESPACE);
+
+ errno = 0;
+ l = strtoul(s, &x, 16);
+ if (errno > 0)
+ return -errno;
+ if (!x || x == s || *x != 0)
+ return -EINVAL;
+ if (s[0] == '-')
+ return -ERANGE;
+ if ((unsigned long) (uint16_t) l != l)
+ return -ERANGE;
+
+ *ret = (uint16_t) l;
+ return 0;
+}
+
int safe_atod(const char *s, double *ret_d) {
+ _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
char *x = NULL;
double d = 0;
- locale_t loc;
assert(s);
assert(ret_d);
static bool arg_auto_start = true;
static bool arg_allow_interactive_authorization = true;
static bool arg_augment_creds = true;
+ static bool arg_watch_bind = false;
static usec_t arg_timeout = 0;
+static int arg_sender_pid = 0;
+static int arg_receiver_pid = 0;
+static bool arg_pid = false;
+static bool arg_dot = false;
+static bool monitor_run_condi = true;
+static bool arg_well_known_names;
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
" --allow-interactive-authorization=BOOL\n"
" Allow interactive authorization for operation\n"
" --timeout=SECS Maximum time to wait for method call completion\n"
- " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
+ " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
+ " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n"
+ " system\n\n"
++ "\n"
+ " --pid=PID Only show messages with pid equals PID\n"
+ " --sender-pid=SENDER_PID\n"
+ " Only show message with sender pid equals SENDER_PID\n"
+ " --receiver-pid=RECEIVER_PID\n"
+ " Only show message with receiver pid equals RECEIVER_PID\n"
+ " --well-known-names=BOOL \n"
+ " Show well know names connected to unique names on graph\n"
"Commands:\n"
" list List bus names\n"
" status [SERVICE] Show bus service, process or bus owner credentials\n"
ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
ARG_TIMEOUT,
ARG_AUGMENT_CREDS,
+ ARG_WATCH_BIND,
+ ARG_PID,
+ ARG_SENDER_PID,
+ ARG_RECEIVER_PID,
+ ARG_WELL_KNOWN_NAMES,
};
static const struct option options[] = {
{ "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
+ { "watch-bind", required_argument, NULL, ARG_WATCH_BIND },
+ { "pid", required_argument, NULL, ARG_PID},
+ { "sender-pid", required_argument, NULL, ARG_SENDER_PID},
+ { "receiver-pid", required_argument, NULL, ARG_RECEIVER_PID},
+ { "well-known-names", required_argument, NULL, ARG_WELL_KNOWN_NAMES},
{},
};
arg_augment_creds = !!r;
break;
+ case ARG_WATCH_BIND:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --watch-bind= parameter.");
+ return r;
+ }
+
+ arg_watch_bind = !!r;
+ break;
+
+ case ARG_PID:
+ arg_pid = true;
+ r = arg_parse_pid(optarg, true, true);
+ if (r < 0)
+ return r;
+ break;
+
+ case ARG_SENDER_PID:
+ r = arg_parse_pid(optarg, true, false);
+ if (r < 0)
+ return 0;
+ break;
+
+ case ARG_RECEIVER_PID:
+ r = arg_parse_pid(optarg, false, true);
+ if (r < 0)
+ return 0;
+ break;
+
+ case ARG_WELL_KNOWN_NAMES:
+ arg_well_known_names = parse_boolean(optarg);
+ break;
+
case '?':
return -EINVAL;
NULSTR_FOREACH_PAIR(x, y, auto_devices)
whitelist_device(path, x, y);
+ /* PTS (/dev/pts) devices may not be duplicated, but accessed */
whitelist_major(path, "pts", 'c', "rw");
+ whitelist_major(path, "kdbus", 'c', "rw");
+ whitelist_major(path, "kdbus/*", 'c', "rw");
}
LIST_FOREACH(device_allow, a, c->device_allow) {
--- /dev/null
- log_set_target(LOG_TARGET_SAFE);
+/***
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#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,
+ 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_prohibit_ipc(true);
++ log_set_target(LOG_TARGET_AUTO);
+ 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;
+}
sd-bus/bus-container.h
sd-bus/bus-control.c
sd-bus/bus-control.h
++ sd-bus/bus-control-kernel.c
++ sd-bus/bus-control-kernel.h
sd-bus/bus-convenience.c
sd-bus/bus-creds.c
sd-bus/bus-creds.h
return -error_buf;
}
- if (si.si_code != CLD_EXITED)
- return -EIO;
-
- if (si.si_status != EXIT_SUCCESS)
- return -EIO;
-
return bus_socket_start_auth(b);
}
+
+int bus_container_connect_kernel(sd_bus *b) {
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ int error_buf = 0;
+ struct iovec iov = {
+ .iov_base = &error_buf,
+ .iov_len = sizeof(error_buf),
+ };
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+ struct cmsghdr *cmsg;
+ pid_t child;
+ siginfo_t si;
+ int r, fd = -1;
+ ssize_t n;
+
+ assert(b);
+ assert(b->input_fd < 0);
+ assert(b->output_fd < 0);
+ assert(b->nspid > 0 || b->machine);
+
+ if (b->nspid <= 0) {
+ r = container_get_leader(b->machine, &b->nspid);
+ if (r < 0)
+ return r;
+ }
+
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ pid_t grandchild;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ /* We just changed PID namespace, however it will only
+ * take effect on the children we now fork. Hence,
+ * let's fork another time, and connect from this
+ * grandchild, so that kdbus only sees the credentials
+ * of this process which comes from within the
+ * container, and not outside of it */
+
+ grandchild = fork();
+ if (grandchild < 0)
+ _exit(EXIT_FAILURE);
+
+ if (grandchild == 0) {
+ fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0) {
+ /* Try to send error up */
+ error_buf = errno;
+ (void) write(pair[1], &error_buf, sizeof(error_buf));
+ _exit(EXIT_FAILURE);
+ }
+
+ r = send_one_fd(pair[1], fd, 0);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate(grandchild, &si);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ if (si.si_code != CLD_EXITED)
+ _exit(EXIT_FAILURE);
+
+ _exit(si.si_status);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+
+ n = recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
+ if (n < 0)
+ return -errno;
+
+ CMSG_FOREACH(cmsg, &mh) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ int *fds;
+ unsigned n_fds;
+
+ assert(fd < 0);
+
+ fds = (int*) CMSG_DATA(cmsg);
+ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+ if (n_fds != 1) {
+ close_many(fds, n_fds);
+ return -EIO;
+ }
+
+ fd = fds[0];
+ }
+ }
+
+ /* If there's an fd passed, we are good. */
+ if (fd >= 0) {
+ b->input_fd = b->output_fd = fd;
+ return bus_kernel_take_fd(b);
+ }
+
+ /* If there's an error passed, use it */
+ if (n == sizeof(error_buf) && error_buf > 0)
+ return -error_buf;
+
+ /* Otherwise, we have no clue */
+ return -EIO;
+}
--- /dev/null
--- /dev/null
++/* SPDX-License-Identifier: LGPL-2.1+ */
++/***
++ 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 <http://www.gnu.org/licenses/>.
++***/
++
++#if HAVE_VALGRIND_MEMCHECK_H
++#include <valgrind/memcheck.h>
++#endif
++
++#include <errno.h>
++#include <stddef.h>
++
++#include "sd-bus.h"
++
++#include "alloc-util.h"
++//#include "bus-bloom.h"
++#include "bus-control-kernel.h"
++#include "bus-internal.h"
++#include "bus-message.h"
++#include "bus-util.h"
++#include "capability-util.h"
++#include "process-util.h"
++#include "stdio-util.h"
++#include "string-util.h"
++#include "strv.h"
++#include "user-util.h"
++
++int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags) {
++ struct kdbus_cmd *n;
++ size_t size, l;
++ int r;
++
++ assert(bus);
++ assert(name);
++
++ l = strlen(name) + 1;
++ size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
++ n = alloca0_align(size, 8);
++ n->size = size;
++ n->flags = request_name_flags_to_kdbus(flags);
++
++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
++ n->items[0].type = KDBUS_ITEM_NAME;
++ memcpy(n->items[0].str, name, l);
++
++#if HAVE_VALGRIND_MEMCHECK_H
++ VALGRIND_MAKE_MEM_DEFINED(n, n->size);
++#endif
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_NAME_ACQUIRE, n);
++ if (r < 0)
++ return -errno;
++
++ if (n->return_flags & KDBUS_NAME_IN_QUEUE)
++ return 0;
++
++ return 1;
++}
++
++int bus_release_name_kernel(sd_bus *bus, const char *name) {
++ struct kdbus_cmd *n;
++ size_t size, l;
++ int r;
++
++ assert(bus);
++ assert(name);
++
++ l = strlen(name) + 1;
++ size = offsetof(struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(l);
++ n = alloca0_align(size, 8);
++ n->size = size;
++
++ n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
++ n->items[0].type = KDBUS_ITEM_NAME;
++ memcpy(n->items[0].str, name, l);
++
++#if HAVE_VALGRIND_MEMCHECK_H
++ VALGRIND_MAKE_MEM_DEFINED(n, n->size);
++#endif
++ r = ioctl(bus->input_fd, KDBUS_CMD_NAME_RELEASE, n);
++ if (r < 0)
++ return -errno;
++
++ return 0;
++}
++
++static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
++ struct kdbus_cmd_list cmd = {
++ .size = sizeof(cmd),
++ .flags = flags,
++ };
++ struct kdbus_info *name_list, *name;
++ uint64_t previous_id = 0;
++ int r;
++
++ /* Caller will free half-constructed list on failure... */
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_LIST, &cmd);
++ if (r < 0)
++ return -errno;
++
++ name_list = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
++
++ KDBUS_FOREACH(name, name_list, cmd.list_size) {
++ struct kdbus_item *item;
++
++ if ((flags & KDBUS_LIST_UNIQUE) && name->id != previous_id && !(name->flags & KDBUS_HELLO_ACTIVATOR)) {
++ char *n;
++
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wformat"
++ if (asprintf(&n, ":1.%llu", name->id) < 0) {
++ r = -ENOMEM;
++ goto fail;
++ }
++#pragma GCC diagnostic pop
++
++ r = strv_consume(x, n);
++ if (r < 0)
++ goto fail;
++
++ previous_id = name->id;
++ }
++
++ KDBUS_ITEM_FOREACH(item, name, items) {
++ if (item->type == KDBUS_ITEM_OWNED_NAME) {
++ if (service_name_is_valid(item->name.name)) {
++ r = strv_extend(x, item->name.name);
++ if (r < 0) {
++ r = -ENOMEM;
++ goto fail;
++ }
++ }
++ }
++ }
++ }
++
++ r = 0;
++
++fail:
++ bus_kernel_cmd_free(bus, cmd.offset);
++ return r;
++}
++
++int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable) {
++ _cleanup_strv_free_ char **x = NULL, **y = NULL;
++ int r;
++
++ if (acquired) {
++ r = kernel_get_list(bus, KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES, &x);
++ if (r < 0)
++ return r;
++ }
++
++ if (activatable) {
++ r = kernel_get_list(bus, KDBUS_LIST_ACTIVATORS, &y);
++ if (r < 0)
++ return r;
++
++ *activatable = y;
++ y = NULL;
++ }
++
++ if (acquired) {
++ *acquired = x;
++ x = NULL;
++ }
++
++ return 0;
++}
++
++static int bus_populate_creds_from_items(
++ sd_bus *bus,
++ struct kdbus_info *info,
++ uint64_t mask,
++ sd_bus_creds *c) {
++
++ struct kdbus_item *item;
++ uint64_t m;
++ int r;
++
++ assert(bus);
++ assert(info);
++ assert(c);
++
++ KDBUS_ITEM_FOREACH(item, info, items) {
++
++ switch (item->type) {
++
++ case KDBUS_ITEM_PIDS:
++
++ if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
++ c->pid = (pid_t) item->pids.pid;
++ c->mask |= SD_BUS_CREDS_PID;
++ }
++
++ if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
++ c->tid = (pid_t) item->pids.tid;
++ c->mask |= SD_BUS_CREDS_TID;
++ }
++
++ if (mask & SD_BUS_CREDS_PPID) {
++ if (item->pids.ppid > 0) {
++ c->ppid = (pid_t) item->pids.ppid;
++ c->mask |= SD_BUS_CREDS_PPID;
++ } else if (item->pids.pid == 1) {
++ /* The structure doesn't
++ * really distinguish the case
++ * where a process has no
++ * parent and where we don't
++ * know it because it could
++ * not be translated due to
++ * namespaces. However, we
++ * know that PID 1 has no
++ * parent process, hence let's
++ * patch that in, manually. */
++ c->ppid = 0;
++ c->mask |= SD_BUS_CREDS_PPID;
++ }
++ }
++
++ break;
++
++ case KDBUS_ITEM_CREDS:
++
++ if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
++ c->uid = (uid_t) item->creds.uid;
++ c->mask |= SD_BUS_CREDS_UID;
++ }
++
++ if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
++ c->euid = (uid_t) item->creds.euid;
++ c->mask |= SD_BUS_CREDS_EUID;
++ }
++
++ if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
++ c->suid = (uid_t) item->creds.suid;
++ c->mask |= SD_BUS_CREDS_SUID;
++ }
++
++ if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
++ c->fsuid = (uid_t) item->creds.fsuid;
++ c->mask |= SD_BUS_CREDS_FSUID;
++ }
++
++ if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
++ c->gid = (gid_t) item->creds.gid;
++ c->mask |= SD_BUS_CREDS_GID;
++ }
++
++ if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
++ c->egid = (gid_t) item->creds.egid;
++ c->mask |= SD_BUS_CREDS_EGID;
++ }
++
++ if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
++ c->sgid = (gid_t) item->creds.sgid;
++ c->mask |= SD_BUS_CREDS_SGID;
++ }
++
++ if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
++ c->fsgid = (gid_t) item->creds.fsgid;
++ c->mask |= SD_BUS_CREDS_FSGID;
++ }
++
++ break;
++
++ case KDBUS_ITEM_PID_COMM:
++ if (mask & SD_BUS_CREDS_COMM) {
++ r = free_and_strdup(&c->comm, item->str);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_COMM;
++ }
++ break;
++
++ case KDBUS_ITEM_TID_COMM:
++ if (mask & SD_BUS_CREDS_TID_COMM) {
++ r = free_and_strdup(&c->tid_comm, item->str);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_TID_COMM;
++ }
++ break;
++
++ case KDBUS_ITEM_EXE:
++ if (mask & SD_BUS_CREDS_EXE) {
++ r = free_and_strdup(&c->exe, item->str);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_EXE;
++ }
++ break;
++
++ case KDBUS_ITEM_CMDLINE:
++ if (mask & SD_BUS_CREDS_CMDLINE) {
++ c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
++ c->cmdline = memdup(item->data, c->cmdline_size);
++ if (!c->cmdline)
++ return -ENOMEM;
++
++ c->mask |= SD_BUS_CREDS_CMDLINE;
++ }
++ break;
++
++ case KDBUS_ITEM_CGROUP:
++ m = (SD_BUS_CREDS_CGROUP | SD_BUS_CREDS_UNIT |
++ SD_BUS_CREDS_USER_UNIT | SD_BUS_CREDS_SLICE |
++ SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
++
++ if (m) {
++ r = free_and_strdup(&c->cgroup, item->str);
++ if (r < 0)
++ return r;
++
++ r = bus_get_root_path(bus);
++ if (r < 0)
++ return r;
++
++ r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
++ if (r < 0)
++ return r;
++
++ c->mask |= m;
++ }
++ break;
++
++ case KDBUS_ITEM_CAPS:
++ m = (SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS |
++ SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_BOUNDING_CAPS) & mask;
++
++ if (m) {
++ if (item->caps.last_cap != cap_last_cap() ||
++ item->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(item->caps.last_cap, 32U) * 4 * 4)
++ return -EBADMSG;
++
++ c->capability = memdup(item->caps.caps, item->size - offsetof(struct kdbus_item, caps.caps));
++ if (!c->capability)
++ return -ENOMEM;
++
++ c->mask |= m;
++ }
++ break;
++
++ case KDBUS_ITEM_SECLABEL:
++ if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
++ r = free_and_strdup(&c->label, item->str);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
++ }
++ break;
++
++ case KDBUS_ITEM_AUDIT:
++ if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
++ c->audit_session_id = (uint32_t) item->audit.sessionid;
++ c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
++ }
++
++ if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
++ c->audit_login_uid = (uid_t) item->audit.loginuid;
++ c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
++ }
++ break;
++
++ case KDBUS_ITEM_OWNED_NAME:
++ if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
++ r = strv_extend(&c->well_known_names, item->name.name);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
++ }
++ break;
++
++ case KDBUS_ITEM_CONN_DESCRIPTION:
++ if (mask & SD_BUS_CREDS_DESCRIPTION) {
++ r = free_and_strdup(&c->description, item->str);
++ if (r < 0)
++ return r;
++
++ c->mask |= SD_BUS_CREDS_DESCRIPTION;
++ }
++ break;
++
++ case KDBUS_ITEM_AUXGROUPS:
++ if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
++ size_t i, n;
++ uid_t *g;
++
++ n = (item->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
++ g = new(gid_t, n);
++ if (!g)
++ return -ENOMEM;
++
++ for (i = 0; i < n; i++)
++ g[i] = item->data64[i];
++
++ free(c->supplementary_gids);
++ c->supplementary_gids = g;
++ c->n_supplementary_gids = n;
++
++ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
++ }
++ break;
++ }
++ }
++
++ return 0;
++}
++
++static uint64_t attach_flags_to_kdbus(uint64_t mask) {
++ uint64_t m = 0;
++
++ if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
++ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID))
++ m |= KDBUS_ATTACH_CREDS;
++
++ if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID))
++ m |= KDBUS_ATTACH_PIDS;
++
++ if (mask & SD_BUS_CREDS_COMM)
++ m |= KDBUS_ATTACH_PID_COMM;
++
++ if (mask & SD_BUS_CREDS_TID_COMM)
++ m |= KDBUS_ATTACH_TID_COMM;
++
++ if (mask & SD_BUS_CREDS_EXE)
++ m |= KDBUS_ATTACH_EXE;
++
++ if (mask & SD_BUS_CREDS_CMDLINE)
++ m |= KDBUS_ATTACH_CMDLINE;
++
++ if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
++ m |= KDBUS_ATTACH_CGROUP;
++
++ if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
++ m |= KDBUS_ATTACH_CAPS;
++
++ if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
++ m |= KDBUS_ATTACH_SECLABEL;
++
++ if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
++ m |= KDBUS_ATTACH_AUDIT;
++
++ if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
++ m |= KDBUS_ATTACH_NAMES;
++
++ if (mask & SD_BUS_CREDS_DESCRIPTION)
++ m |= KDBUS_ATTACH_CONN_DESCRIPTION;
++
++ if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS)
++ m |= KDBUS_ATTACH_AUXGROUPS;
++
++ return m;
++}
++
++int bus_get_name_creds_kdbus(
++ sd_bus *bus,
++ const char *name,
++ uint64_t mask,
++ bool allow_activator,
++ sd_bus_creds **creds) {
++
++ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
++ struct kdbus_cmd_info *cmd;
++ struct kdbus_info *conn_info;
++ size_t size, l;
++ uint64_t id;
++ int r;
++
++ if (streq(name, "org.freedesktop.DBus"))
++ return -EOPNOTSUPP;
++
++ r = bus_kernel_parse_unique_name(name, &id);
++ if (r < 0)
++ return r;
++ if (r > 0) {
++ size = offsetof(struct kdbus_cmd_info, items);
++ cmd = alloca0_align(size, 8);
++ cmd->id = id;
++ } else {
++ l = strlen(name) + 1;
++ size = offsetof(struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(l);
++ cmd = alloca0_align(size, 8);
++ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
++ cmd->items[0].type = KDBUS_ITEM_NAME;
++ memcpy(cmd->items[0].str, name, l);
++ }
++
++ /* If augmentation is on, and the bus didn't provide us
++ * the bits we want, then ask for the PID/TID so that we
++ * can read the rest from /proc. */
++ if ((mask & SD_BUS_CREDS_AUGMENT) &&
++ (mask & (SD_BUS_CREDS_PPID|
++ SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
++ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
++ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
++ SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
++ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
++ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
++ SD_BUS_CREDS_SELINUX_CONTEXT|
++ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
++ mask |= SD_BUS_CREDS_PID;
++
++ cmd->size = size;
++ cmd->attach_flags = attach_flags_to_kdbus(mask);
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
++ if (r < 0)
++ return -errno;
++
++ conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
++
++ /* Non-activated names are considered not available */
++ if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
++ if (name[0] == ':')
++ r = -ENXIO;
++ else
++ r = -ESRCH;
++ goto fail;
++ }
++
++ c = bus_creds_new();
++ if (!c) {
++ r = -ENOMEM;
++ goto fail;
++ }
++
++ if (mask & SD_BUS_CREDS_UNIQUE_NAME) {
++#pragma GCC diagnostic push
++#pragma GCC diagnostic ignored "-Wformat"
++ if (asprintf(&c->unique_name, ":1.%llu", conn_info->id) < 0) {
++ r = -ENOMEM;
++ goto fail;
++ }
++#pragma GCC diagnostic pop
++
++ c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
++ }
++
++ /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
++ them in case the service has no names. This does not mean
++ however that the list of owned names could not be
++ acquired. Hence, let's explicitly clarify that the data is
++ complete. */
++ c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
++
++ r = bus_populate_creds_from_items(bus, conn_info, mask, c);
++ if (r < 0)
++ goto fail;
++
++ r = bus_creds_add_more(c, mask, 0, 0);
++ if (r < 0)
++ goto fail;
++
++ if (creds) {
++ *creds = c;
++ c = NULL;
++ }
++
++ r = 0;
++
++fail:
++ bus_kernel_cmd_free(bus, cmd->offset);
++ return r;
++}
++
++int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
++ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
++ struct kdbus_cmd_info cmd = {
++ .size = sizeof(struct kdbus_cmd_info),
++ };
++ struct kdbus_info *creator_info;
++ pid_t pid = 0;
++ int r;
++
++ c = bus_creds_new();
++ if (!c)
++ return -ENOMEM;
++
++ /* If augmentation is on, and the bus doesn't didn't allow us
++ * to get the bits we want, then ask for the PID/TID so that we
++ * can read the rest from /proc. */
++ if ((mask & SD_BUS_CREDS_AUGMENT) &&
++ (mask & (SD_BUS_CREDS_PPID|
++ SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
++ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
++ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
++ SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
++ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
++ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
++ SD_BUS_CREDS_SELINUX_CONTEXT|
++ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
++ mask |= SD_BUS_CREDS_PID;
++
++ cmd.attach_flags = attach_flags_to_kdbus(mask);
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
++ if (r < 0)
++ return -errno;
++
++ creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
++
++ r = bus_populate_creds_from_items(bus, creator_info, mask, c);
++ bus_kernel_cmd_free(bus, cmd.offset);
++ if (r < 0)
++ return r;
++
++ r = bus_creds_add_more(c, mask, pid, 0);
++ if (r < 0)
++ return r;
++
++ *ret = c;
++ c = NULL;
++ return 0;
++}
++
++static int add_name_change_match(sd_bus *bus,
++ uint64_t cookie,
++ const char *name,
++ const char *old_owner,
++ const char *new_owner) {
++
++ uint64_t name_id = KDBUS_MATCH_ID_ANY, old_owner_id = 0, new_owner_id = 0;
++ int is_name_id = -1, r;
++ struct kdbus_item *item;
++
++ assert(bus);
++
++ /* If we encounter a match that could match against
++ * NameOwnerChanged messages, then we need to create
++ * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} and
++ * KDBUS_ITEM_ID_{ADD,REMOVE} matches for it, possibly
++ * multiple if the match is underspecified.
++ *
++ * The NameOwnerChanged signals take three parameters with
++ * unique or well-known names, but only some forms actually
++ * exist:
++ *
++ * WELLKNOWN, "", UNIQUE → KDBUS_ITEM_NAME_ADD
++ * WELLKNOWN, UNIQUE, "" → KDBUS_ITEM_NAME_REMOVE
++ * WELLKNOWN, UNIQUE, UNIQUE → KDBUS_ITEM_NAME_CHANGE
++ * UNIQUE, "", UNIQUE → KDBUS_ITEM_ID_ADD
++ * UNIQUE, UNIQUE, "" → KDBUS_ITEM_ID_REMOVE
++ *
++ * For the latter two the two unique names must be identical.
++ *
++ * */
++
++ if (name) {
++ is_name_id = bus_kernel_parse_unique_name(name, &name_id);
++ if (is_name_id < 0)
++ return 0;
++ }
++
++ if (!isempty(old_owner)) {
++ r = bus_kernel_parse_unique_name(old_owner, &old_owner_id);
++ if (r < 0)
++ return 0;
++ if (r == 0)
++ return 0;
++ if (is_name_id > 0 && old_owner_id != name_id)
++ return 0;
++ } else
++ old_owner_id = KDBUS_MATCH_ID_ANY;
++
++ if (!isempty(new_owner)) {
++ r = bus_kernel_parse_unique_name(new_owner, &new_owner_id);
++ if (r < 0)
++ return r;
++ if (r == 0)
++ return 0;
++ if (is_name_id > 0 && new_owner_id != name_id)
++ return 0;
++ } else
++ new_owner_id = KDBUS_MATCH_ID_ANY;
++
++ if (is_name_id <= 0) {
++ struct kdbus_cmd_match *m;
++ size_t sz, l;
++
++ /* If the name argument is missing or is a well-known
++ * name, then add KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}
++ * matches for it */
++
++ l = name ? strlen(name) + 1 : 0;
++
++ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
++ offsetof(struct kdbus_item, name_change) +
++ offsetof(struct kdbus_notify_name_change, name) +
++ l);
++
++ m = alloca0_align(sz, 8);
++ m->size = sz;
++ m->cookie = cookie;
++
++ item = m->items;
++ item->size =
++ offsetof(struct kdbus_item, name_change) +
++ offsetof(struct kdbus_notify_name_change, name) +
++ l;
++
++ item->name_change.old_id.id = old_owner_id;
++ item->name_change.new_id.id = new_owner_id;
++
++ memcpy_safe(item->name_change.name, name, l);
++
++ /* If the old name is unset or empty, then
++ * this can match against added names */
++ if (isempty(old_owner)) {
++ item->type = KDBUS_ITEM_NAME_ADD;
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++ }
++
++ /* If the new name is unset or empty, then
++ * this can match against removed names */
++ if (isempty(new_owner)) {
++ item->type = KDBUS_ITEM_NAME_REMOVE;
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++ }
++
++ /* The CHANGE match we need in either case, because
++ * what is reported as a name change by the kernel
++ * might just be an owner change between starter and
++ * normal clients. For userspace such a change should
++ * be considered a removal/addition, hence let's
++ * subscribe to this unconditionally. */
++ item->type = KDBUS_ITEM_NAME_CHANGE;
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++ }
++
++ if (is_name_id != 0) {
++ struct kdbus_cmd_match *m;
++ uint64_t sz;
++
++ /* If the name argument is missing or is a unique
++ * name, then add KDBUS_ITEM_ID_{ADD,REMOVE} matches
++ * for it */
++
++ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items) +
++ offsetof(struct kdbus_item, id_change) +
++ sizeof(struct kdbus_notify_id_change));
++
++ m = alloca0_align(sz, 8);
++ m->size = sz;
++ m->cookie = cookie;
++
++ item = m->items;
++ item->size =
++ offsetof(struct kdbus_item, id_change) +
++ sizeof(struct kdbus_notify_id_change);
++ item->id_change.id = name_id;
++
++ /* If the old name is unset or empty, then this can
++ * match against added ids */
++ if (isempty(old_owner)) {
++ item->type = KDBUS_ITEM_ID_ADD;
++ if (!isempty(new_owner))
++ item->id_change.id = new_owner_id;
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++ }
++
++ /* If thew new name is unset or empty, then this can
++ * match against removed ids */
++ if (isempty(new_owner)) {
++ item->type = KDBUS_ITEM_ID_REMOVE;
++ if (!isempty(old_owner))
++ item->id_change.id = old_owner_id;
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++ }
++ }
++
++ return 0;
++}
++
++int bus_add_match_internal_kernel(
++ sd_bus *bus,
++ struct bus_match_component *components,
++ unsigned n_components,
++ uint64_t cookie) {
++
++ struct kdbus_cmd_match *m;
++ struct kdbus_item *item;
++ uint64_t *bloom;
++ size_t sz;
++ const char *sender = NULL;
++ size_t sender_length = 0;
++ uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY;
++ bool using_bloom = false;
++ unsigned i;
++ bool matches_name_change = true;
++ const char *name_change_arg[3] = {};
++ int r;
++
++ assert(bus);
++
++ /* Monitor streams don't support matches, make this a NOP */
++ //if (bus->hello_flags & KDBUS_HELLO_MONITOR)
++ //return 0;
++
++ bloom = alloca0(bus->bloom_size);
++
++ sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
++
++ for (i = 0; i < n_components; i++) {
++ struct bus_match_component *c = &components[i];
++
++ switch (c->type) {
++
++ case BUS_MATCH_SENDER:
++ if (!streq(c->value_str, "org.freedesktop.DBus"))
++ matches_name_change = false;
++
++ r = bus_kernel_parse_unique_name(c->value_str, &src_id);
++ if (r < 0)
++ return r;
++ else if (r > 0)
++ sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
++ else {
++ sender = c->value_str;
++ sender_length = strlen(sender);
++ sz += ALIGN8(offsetof(struct kdbus_item, str) + sender_length + 1);
++ }
++
++ break;
++
++ case BUS_MATCH_MESSAGE_TYPE:
++ if (c->value_u8 != SD_BUS_MESSAGE_SIGNAL)
++ matches_name_change = false;
++
++// bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "message-type", bus_message_type_to_string(c->value_u8));
++ using_bloom = true;
++ break;
++
++ case BUS_MATCH_INTERFACE:
++ if (!streq(c->value_str, "org.freedesktop.DBus"))
++ matches_name_change = false;
++
++// bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "interface", c->value_str);
++ using_bloom = true;
++ break;
++
++ case BUS_MATCH_MEMBER:
++ if (!streq(c->value_str, "NameOwnerChanged"))
++ matches_name_change = false;
++
++// bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "member", c->value_str);
++ using_bloom = true;
++ break;
++
++ case BUS_MATCH_PATH:
++ if (!streq(c->value_str, "/org/freedesktop/DBus"))
++ matches_name_change = false;
++
++ //bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path", c->value_str);
++ using_bloom = true;
++ break;
++
++ case BUS_MATCH_PATH_NAMESPACE:
++ //bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, "path-slash-prefix", c->value_str);
++ using_bloom = true;
++ break;
++
++ case BUS_MATCH_ARG...BUS_MATCH_ARG_LAST: {
++ char buf[sizeof("arg")-1 + 2 + 1];
++
++ if (c->type - BUS_MATCH_ARG < 3)
++ name_change_arg[c->type - BUS_MATCH_ARG] = c->value_str;
++
++ xsprintf(buf, "arg%i", c->type - BUS_MATCH_ARG);
++ //bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
++ using_bloom = true;
++ break;
++ }
++
++ case BUS_MATCH_ARG_HAS...BUS_MATCH_ARG_HAS_LAST: {
++ char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
++
++ xsprintf(buf, "arg%i-has", c->type - BUS_MATCH_ARG_HAS);
++ //bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
++ using_bloom = true;
++ break;
++ }
++
++ case BUS_MATCH_ARG_PATH...BUS_MATCH_ARG_PATH_LAST:
++ /*
++ * XXX: DBus spec defines arg[0..63]path= matching to be
++ * a two-way glob. That is, if either string is a prefix
++ * of the other, it matches.
++ * This is really hard to realize in bloom-filters, as
++ * we would have to create a bloom-match for each prefix
++ * of @c->value_str. This is excessive, hence we just
++ * ignore all those matches and accept everything from
++ * the kernel. People should really avoid those matches.
++ * If they're used in real-life some day, we will have
++ * to properly support multiple-matches here.
++ */
++ break;
++
++ case BUS_MATCH_ARG_NAMESPACE...BUS_MATCH_ARG_NAMESPACE_LAST: {
++ char buf[sizeof("arg")-1 + 2 + sizeof("-dot-prefix")];
++
++ xsprintf(buf, "arg%i-dot-prefix", c->type - BUS_MATCH_ARG_NAMESPACE);
++ //bloom_add_pair(bloom, bus->bloom_size, bus->bloom_n_hash, buf, c->value_str);
++ using_bloom = true;
++ break;
++ }
++
++ case BUS_MATCH_DESTINATION:
++ /*
++ * Kernel only supports matching on destination IDs, but
++ * not on destination names. So just skip the
++ * destination name restriction and verify it in
++ * user-space on retrieval.
++ */
++ r = bus_kernel_parse_unique_name(c->value_str, &dst_id);
++ if (r < 0)
++ return r;
++ else if (r > 0)
++ sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t));
++
++ /* if not a broadcast, it cannot be a name-change */
++ if (r <= 0 || dst_id != KDBUS_DST_ID_BROADCAST)
++ matches_name_change = false;
++
++ break;
++
++ case BUS_MATCH_ROOT:
++ case BUS_MATCH_VALUE:
++ case BUS_MATCH_LEAF:
++ case _BUS_MATCH_NODE_TYPE_MAX:
++ case _BUS_MATCH_NODE_TYPE_INVALID:
++ assert_not_reached("Invalid match type?");
++ }
++ }
++
++ if (using_bloom)
++ sz += ALIGN8(offsetof(struct kdbus_item, data64) + bus->bloom_size);
++
++ m = alloca0_align(sz, 8);
++ m->size = sz;
++ m->cookie = cookie;
++
++ item = m->items;
++
++ if (src_id != KDBUS_MATCH_ID_ANY) {
++ item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
++ item->type = KDBUS_ITEM_ID;
++ item->id = src_id;
++ item = KDBUS_ITEM_NEXT(item);
++ }
++
++ if (dst_id != KDBUS_MATCH_ID_ANY) {
++ item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t);
++ item->type = KDBUS_ITEM_DST_ID;
++ item->id = dst_id;
++ item = KDBUS_ITEM_NEXT(item);
++ }
++
++ if (using_bloom) {
++ item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size;
++ item->type = KDBUS_ITEM_BLOOM_MASK;
++ memcpy(item->data64, bloom, bus->bloom_size);
++ item = KDBUS_ITEM_NEXT(item);
++ }
++
++ if (sender) {
++ item->size = offsetof(struct kdbus_item, str) + sender_length + 1;
++ item->type = KDBUS_ITEM_NAME;
++ memcpy(item->str, sender, sender_length + 1);
++ }
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m);
++ if (r < 0)
++ return -errno;
++
++ if (matches_name_change) {
++
++ /* If this match could theoretically match
++ * NameOwnerChanged messages, we need to
++ * install a second non-bloom filter explitly
++ * for it */
++
++ r = add_name_change_match(bus, cookie, name_change_arg[0], name_change_arg[1], name_change_arg[2]);
++ if (r < 0)
++ return r;
++ }
++
++ return 0;
++}
++
++int bus_remove_match_internal_kernel(
++ sd_bus *bus,
++ uint64_t cookie) {
++
++ struct kdbus_cmd_match m = {
++ .size = offsetof(struct kdbus_cmd_match, items),
++ .cookie = cookie,
++ };
++ int r;
++
++ assert(bus);
++
++ /* Monitor streams don't support matches, make this a NOP */
++ //if (bus->hello_flags & KDBUS_HELLO_MONITOR)
++ //return 0;
++
++ r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_REMOVE, &m);
++ if (r < 0)
++ return -errno;
++
++ return 0;
++}
--- /dev/null
--- /dev/null
++/* SPDX-License-Identifier: LGPL-2.1+ */
++#pragma once
++
++/***
++ 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 <http://www.gnu.org/licenses/>.
++***/
++
++#include "sd-bus.h"
++#include "bus-match.h"
++
++int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags);
++int bus_release_name_kernel(sd_bus *bus, const char *name);
++int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activatable);
++int bus_get_name_creds_kdbus(
++ sd_bus *bus,
++ const char *name,
++ uint64_t mask,
++ bool allow_activator,
++ sd_bus_creds **creds);
++int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret);
++int bus_add_match_internal_kernel(
++ sd_bus *bus,
++ struct bus_match_component *components,
++ unsigned n_components,
++ uint64_t cookie);
++int bus_remove_match_internal_kernel(
++ sd_bus *bus,
++ uint64_t cookie);
#include "sd-bus.h"
#include "alloc-util.h"
- #include "bus-bloom.h"
#include "bus-control.h"
++#include "bus-control-kernel.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
uint32_t ret, param = 0;
int r;
- assert(bus);
- assert(name);
+ assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
+ assert_return(name, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
- if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
- param |= BUS_NAME_ALLOW_REPLACEMENT;
- if (flags & SD_BUS_NAME_REPLACE_EXISTING)
- param |= BUS_NAME_REPLACE_EXISTING;
- if (!(flags & SD_BUS_NAME_QUEUE))
- param |= BUS_NAME_DO_NOT_QUEUE;
+ r = validate_request_name_parameters(bus, name, flags, ¶m);
+ if (r < 0)
+ return r;
+
++ if (bus->is_kernel)
++ return bus_request_name_kernel(bus, name, flags);
+
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
uint32_t ret;
int r;
- assert(bus);
- assert(name);
+ assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
+ assert_return(name, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ r = validate_release_name_parameters(bus, name);
+ if (r < 0)
+ return r;
+
++ if (bus->is_kernel)
++ return bus_release_name_kernel(bus, name);
+
r = sd_bus_call_method(
bus,
"org.freedesktop.DBus",
_cleanup_strv_free_ char **x = NULL, **y = NULL;
int r;
+ assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
+ assert_return(acquired || activatable, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
++ if (bus->is_kernel)
++ return bus_list_names_kernel(bus, acquired, activatable);
++
if (acquired) {
r = sd_bus_call_method(
bus,
pid_t pid = 0;
int r;
+ assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
+ assert_return(name, -EINVAL);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(mask == 0 || creds, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+ assert_return(service_name_is_valid(name), -EINVAL);
+
+ if (!bus->bus_client)
+ return -EINVAL;
+
+ /* Turn off augmenting if this isn't a local connection. If the connection is not local, then /proc is not
+ * going to match. */
+ if (!bus->is_local)
+ mask &= ~SD_BUS_CREDS_AUGMENT;
+
+ if (streq(name, "org.freedesktop.DBus.Local"))
+ return -EINVAL;
+
+ if (streq(name, "org.freedesktop.DBus"))
+ return sd_bus_get_owner_creds(bus, mask, creds);
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
++ if (bus->is_kernel)
++ return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
++
/* Only query the owner if the caller wants to know it or if
* the caller just wants to check whether a name exists */
if ((mask & SD_BUS_CREDS_UNIQUE_NAME) || mask == 0) {
if (!bus->is_local)
mask &= ~SD_BUS_CREDS_AUGMENT;
- if (streq(name, "org.freedesktop.DBus.Local"))
- return -EINVAL;
-
- if (streq(name, "org.freedesktop.DBus"))
- return sd_bus_get_owner_creds(bus, mask, creds);
-
- if (!BUS_IS_OPEN(bus->state))
- return -ENOTCONN;
-
+ if (bus->is_kernel)
- return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
- else
- return bus_get_name_creds_dbus1(bus, name, mask, creds);
- }
-
- static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- struct kdbus_cmd_info cmd = {
- .size = sizeof(struct kdbus_cmd_info),
- };
- struct kdbus_info *creator_info;
- pid_t pid = 0;
- int r;
-
- c = bus_creds_new();
- if (!c)
- return -ENOMEM;
-
- /* If augmentation is on, and the bus doesn't didn't allow us
- * to get the bits we want, then ask for the PID/TID so that we
- * can read the rest from /proc. */
- if ((mask & SD_BUS_CREDS_AUGMENT) &&
- (mask & (SD_BUS_CREDS_PPID|
- SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
- SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
- SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
- SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
- SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
- SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
- SD_BUS_CREDS_SELINUX_CONTEXT|
- SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
- mask |= SD_BUS_CREDS_PID;
-
- cmd.attach_flags = attach_flags_to_kdbus(mask);
-
- r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
- if (r < 0)
- return -errno;
-
- creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
-
- r = bus_populate_creds_from_items(bus, creator_info, mask, c);
- bus_kernel_cmd_free(bus, cmd.offset);
- if (r < 0)
- return r;
-
- r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0)
- return r;
-
- *ret = c;
- c = NULL;
- return 0;
- }
-
- static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- pid_t pid = 0;
- bool do_label;
- int r;
-
- assert(bus);
++ return bus_get_owner_creds_kdbus(bus, mask, ret);
+
do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
+ do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
/* Avoid allocating anything if we have no chance of returning useful data */
- if (!bus->ucred_valid && !do_label)
+ if (!bus->ucred_valid && !do_label && !do_groups)
return -ENODATA;
c = bus_creds_new();
? (isempty(m) ? "eavesdrop='true'" : strjoina((m), ",eavesdrop='true'")) \
: (m))
- static int bus_add_match_internal_dbus1(
+ int bus_add_match_internal(
sd_bus *bus,
-- const char *match) {
++ const char *match,
++ uint64_t cookie) {
const char *e;
assert(bus);
- assert(match);
- e = internal_match(bus, match);
+ if (!bus->bus_client)
+ return -EINVAL;
+
++ if (bus->is_kernel)
++ return bus_add_match_internal_kernel(bus, NULL, 0, cookie);
++
+ e = append_eavesdrop(bus, match);
return sd_bus_call_method(
bus,
int bus_remove_match_internal(
sd_bus *bus,
- const char *match) {
+ const char *match,
+ uint64_t cookie) {
+ const char *e;
+
assert(bus);
+ assert(match);
if (!bus->bus_client)
return -EINVAL;
- else
- return bus_remove_match_internal_dbus1(bus, match);
+ if (bus->is_kernel)
+ return bus_remove_match_internal_kernel(bus, cookie);
++
+ e = append_eavesdrop(bus, match);
+
+ /* Fire and forget */
+
+ return sd_bus_call_method_async(
+ bus,
+ NULL,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "RemoveMatch",
+ NULL,
+ NULL,
+ "s",
+ e);
}
_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
#include "sd-bus.h"
- #include "bus-match.h"
-
- int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
-int bus_add_match_internal(sd_bus *bus, const char *match);
++int bus_add_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
+ int bus_add_match_internal_async(sd_bus *bus, sd_bus_slot **ret, const char *match, sd_bus_message_handler_t callback, void *userdata);
-
-int bus_remove_match_internal(sd_bus *bus, const char *match);
+int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
-
- int bus_add_match_internal_kernel(sd_bus *bus, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
- int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t cookie);
-
- int bus_get_name_creds_kdbus(sd_bus *bus, const char *name, uint64_t mask, bool allow_activator, sd_bus_creds **creds);
struct match_callback {
sd_bus_message_handler_t callback;
+ sd_bus_message_handler_t install_callback;
+
+ sd_bus_slot *install_slot; /* The AddMatch() call */
+ uint64_t cookie;
unsigned last_iteration;
char *match_string;
pid_t original_pid;
- uint64_t hello_flags;
- uint64_t attach_flags;
-
+ uint64_t match_cookie;
+
sd_event_source *input_io_event_source;
sd_event_source *output_io_event_source;
sd_event_source *time_event_source;
char *cgroup_root;
char *description;
+ char *patch_sender;
+ size_t bloom_size;
+ unsigned bloom_n_hash;
+
sd_bus_track *track_queue;
LIST_HEAD(sd_bus_slot, slots);
#include "user-util.h"
#include "util.h"
-void close_and_munmap(int fd, void *address, size_t size) {
+#pragma GCC diagnostic ignored "-Wformat"
+
+#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
+
+int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
+ int r;
+
+ assert(s);
+ assert(id);
+
+ if (!startswith(s, ":1."))
+ return 0;
+
+ r = safe_atou64(s + 3, id);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
+ assert(d);
+ assert(sz > 0);
+
+ *d = ALIGN8_PTR(*d);
+
+ /* Note that p can be NULL, which encodes a region full of
+ * zeroes, which is useful to optimize certain padding
+ * conditions */
+
+ (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
+ (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
+ (*d)->vec.address = PTR_TO_UINT64(p);
+ (*d)->vec.size = sz;
+
+ *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) {
+ assert(d);
+ assert(memfd >= 0);
+ assert(sz > 0);
+
+ *d = ALIGN8_PTR(*d);
+ (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
+ (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
+ (*d)->memfd.fd = memfd;
+ (*d)->memfd.start = start;
+ (*d)->memfd.size = sz;
+
+ *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
+ assert(d);
+ assert(s);
+
+ *d = ALIGN8_PTR(*d);
+
+ (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
+ (*d)->type = KDBUS_ITEM_DST_NAME;
+ memcpy((*d)->str, s, length + 1);
+
+ *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
+ struct kdbus_item *i;
+
+ assert(d);
+
+ i = ALIGN8_PTR(*d);
+
+ i->size = offsetof(struct kdbus_item, bloom_filter) +
+ offsetof(struct kdbus_bloom_filter, data) +
+ length;
+ i->type = KDBUS_ITEM_BLOOM_FILTER;
+
+ *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
+
+ return &i->bloom_filter;
+}
+
+static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
+ assert(d);
+ assert(fds);
+ assert(n_fds > 0);
+
+ *d = ALIGN8_PTR(*d);
+ (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
+ (*d)->type = KDBUS_ITEM_FDS;
+ memcpy((*d)->fds, fds, sizeof(int) * n_fds);
+
+ *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
+}
+
+static void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
+ char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+ char *e;
+
+ assert(data);
+ assert(size > 0);
+ assert(i < 64);
+ assert(t);
+
+ e = stpcpy(buf, "arg");
+ if (i < 10)
+ *(e++) = '0' + (char) i;
+ else {
+ *(e++) = '0' + (char) (i / 10);
+ *(e++) = '0' + (char) (i % 10);
+ }
+
+ *e = 0;
- bloom_add_pair(data, size, n_hash, buf, t);
++ //bloom_add_pair(data, size, n_hash, buf, t);
+
+ strcpy(e, "-dot-prefix");
- bloom_add_prefixes(data, size, n_hash, buf, t, '.');
++ //bloom_add_prefixes(data, size, n_hash, buf, t, '.');
+ strcpy(e, "-slash-prefix");
- bloom_add_prefixes(data, size, n_hash, buf, t, '/');
++ //bloom_add_prefixes(data, size, n_hash, buf, t, '/');
+}
+
+static void add_bloom_arg_has(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
+ char buf[sizeof("arg")-1 + 2 + sizeof("-has")];
+ char *e;
+
+ assert(data);
+ assert(size > 0);
+ assert(i < 64);
+ assert(t);
+
+ e = stpcpy(buf, "arg");
+ if (i < 10)
+ *(e++) = '0' + (char) i;
+ else {
+ *(e++) = '0' + (char) (i / 10);
+ *(e++) = '0' + (char) (i % 10);
+ }
+
+ strcpy(e, "-has");
- bloom_add_pair(data, size, n_hash, buf, t);
++ //bloom_add_pair(data, size, n_hash, buf, t);
+}
+
+static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
+ void *data;
+ unsigned i;
+ int r;
+
+ assert(m);
+ assert(bloom);
+
+ data = bloom->data;
+ memzero(data, m->bus->bloom_size);
+ bloom->generation = 0;
+
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
++ //bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
+
- if (m->interface)
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
- if (m->member)
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
- if (m->path) {
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path);
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path);
- bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
- }
++ //if (m->interface)
++ //bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
++ //if (m->member)
++ //bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
++ //if (m->path) {
++ //bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path);
++ //bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path);
++ //bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
++ //}
+
+ r = sd_bus_message_rewind(m, true);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < 64; i++) {
+ const char *t, *contents;
+ char type;
+
+ r = sd_bus_message_peek_type(m, &type, &contents);
+ if (r < 0)
+ return r;
+
+ if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
+
+ /* The bloom filter includes simple strings of any kind */
+ r = sd_bus_message_read_basic(m, type, &t);
+ if (r < 0)
+ return r;
+
+ add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
+ }
+
+ if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) {
+
+ /* As well as array of simple strings of any kinds */
+ r = sd_bus_message_enter_container(m, type, contents);
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0)
+ add_bloom_arg_has(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+
+ } else
+ /* Stop adding to bloom filter as soon as we
+ * run into the first argument we cannot add
+ * to it. */
+ break;
+ }
+
+ return 0;
+}
+
+static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
+ struct bus_body_part *part;
+ struct kdbus_item *d;
+ const char *destination;
+ bool well_known = false;
+ uint64_t dst_id;
+ size_t sz, dl;
+ unsigned i;
+ int r;
+
+ assert(b);
+ assert(m);
+ assert(m->sealed);
+
+ /* We put this together only once, if this message is reused
+ * we reuse the earlier-built version */
+ if (m->kdbus)
+ return 0;
+
- destination = m->destination ?: m->destination_ptr;
++ //destination = m->destination ?: m->destination_ptr;
+
+ if (destination) {
+ r = bus_kernel_parse_unique_name(destination, &dst_id);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ well_known = true;
+
+ /* verify_destination_id will usually be 0, which makes the kernel
+ * driver only look at the provided well-known name. Otherwise,
+ * the kernel will make sure the provided destination id matches
+ * the owner of the provided well-known-name, and fail if they
+ * differ. Currently, this is only needed for bus-proxyd. */
+ dst_id = m->verify_destination_id;
+ }
+ } else
+ dst_id = KDBUS_DST_ID_BROADCAST;
+
+ sz = offsetof(struct kdbus_msg, items);
+
+ /* Add in fixed header, fields header and payload */
+ sz += (1 + m->n_body_parts) * ALIGN8(offsetof(struct kdbus_item, vec) +
+ MAX(sizeof(struct kdbus_vec),
+ sizeof(struct kdbus_memfd)));
+
+ /* Add space for bloom filter */
+ sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) +
+ offsetof(struct kdbus_bloom_filter, data) +
+ m->bus->bloom_size);
+
+ /* Add in well-known destination header */
+ if (well_known) {
+ dl = strlen(destination);
+ sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
+ }
+
+ /* Add space for unix fds */
+ if (m->n_fds > 0)
+ sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
+
+ m->kdbus = memalign(8, sz);
+ if (!m->kdbus) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ m->free_kdbus = true;
+ memzero(m->kdbus, sz);
+
+ m->kdbus->flags =
+ ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_EXPECT_REPLY) |
+ ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0) |
+ ((m->header->type == SD_BUS_MESSAGE_SIGNAL) ? KDBUS_MSG_SIGNAL : 0);
+
+ m->kdbus->dst_id = dst_id;
+ m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
+ m->kdbus->cookie = m->header->dbus2.cookie;
+ m->kdbus->priority = m->priority;
+
+ if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
+ m->kdbus->cookie_reply = m->reply_cookie;
+ else {
+ struct timespec now;
+
+ assert_se(clock_gettime(CLOCK_MONOTONIC_COARSE, &now) == 0);
+ m->kdbus->timeout_ns = now.tv_sec * NSEC_PER_SEC + now.tv_nsec +
+ m->timeout * NSEC_PER_USEC;
+ }
+
+ d = m->kdbus->items;
+
+ if (well_known)
+ append_destination(&d, destination, dl);
+
+ append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
+
+ MESSAGE_FOREACH_PART(part, i, m) {
+ if (part->is_zero) {
+ /* If this is padding then simply send a
+ * vector with a NULL data pointer which the
+ * kernel will just pass through. This is the
+ * most efficient way to encode zeroes */
+
+ append_payload_vec(&d, NULL, part->size);
+ continue;
+ }
+
+ if (part->memfd >= 0 && part->sealed && destination) {
+ /* Try to send a memfd, if the part is
+ * sealed and this is not a broadcast. Since we can only */
+
+ append_payload_memfd(&d, part->memfd, part->memfd_offset, part->size);
+ continue;
+ }
+
+ /* Otherwise, let's send a vector to the actual data.
+ * For that, we need to map it first. */
+ r = bus_body_part_map(part);
+ if (r < 0)
+ goto fail;
+
+ append_payload_vec(&d, part->data, part->size);
+ }
+
+ if (m->header->type == SD_BUS_MESSAGE_SIGNAL) {
+ struct kdbus_bloom_filter *bloom;
+
+ bloom = append_bloom(&d, m->bus->bloom_size);
+ r = bus_message_setup_bloom(m, bloom);
+ if (r < 0)
+ goto fail;
+ }
+
+ if (m->n_fds > 0)
+ append_fds(&d, m->fds, m->n_fds);
+
+ m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
+ assert(m->kdbus->size <= sz);
+
+ return 0;
+
+fail:
+ m->poisoned = true;
+ return r;
+}
+
+static void unset_memfds(struct sd_bus_message *m) {
+ struct bus_body_part *part;
+ unsigned i;
+
+ assert(m);
+
+ /* Make sure the memfds are not freed twice */
+ MESSAGE_FOREACH_PART(part, i, m)
+ if (part->memfd >= 0)
+ part->memfd = -1;
+}
+
+static void message_set_timestamp(sd_bus *bus, sd_bus_message *m, const struct kdbus_timestamp *ts) {
+ assert(bus);
+ assert(m);
+
+ if (!ts)
+ return;
+
- if (!(bus->attach_flags & KDBUS_ATTACH_TIMESTAMP))
- return;
++ //if (!(bus->attach_flags & KDBUS_ATTACH_TIMESTAMP))
++ //return;
+
+ m->realtime = ts->realtime_ns / NSEC_PER_USEC;
+ m->monotonic = ts->monotonic_ns / NSEC_PER_USEC;
+ m->seqnum = ts->seqnum;
+}
+
+static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
+ sd_bus_message *m = NULL;
+ struct kdbus_item *d;
+ unsigned n_fds = 0;
+ _cleanup_free_ int *fds = NULL;
+ struct bus_header *header = NULL;
+ void *footer = NULL;
+ size_t header_size = 0, footer_size = 0;
+ size_t n_bytes = 0, idx = 0;
+ const char *destination = NULL, *seclabel = NULL;
+ bool last_was_memfd = false;
+ int r;
+
+ assert(bus);
+ assert(k);
+ assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ size_t l;
+
+ l = d->size - offsetof(struct kdbus_item, data);
+
+ switch (d->type) {
+
+ case KDBUS_ITEM_PAYLOAD_OFF:
+ if (!header) {
+ header = (struct bus_header*)((uint8_t*) k + d->vec.offset);
+ header_size = d->vec.size;
+ }
+
+ footer = (uint8_t*) k + d->vec.offset;
+ footer_size = d->vec.size;
+
+ n_bytes += d->vec.size;
+ last_was_memfd = false;
+ break;
+
+ case KDBUS_ITEM_PAYLOAD_MEMFD:
+ if (!header) /* memfd cannot be first part */
+ return -EBADMSG;
+
+ n_bytes += d->memfd.size;
+ last_was_memfd = true;
+ break;
+
+ case KDBUS_ITEM_FDS: {
+ int *f;
+ unsigned j;
+
+ j = l / sizeof(int);
+ f = realloc(fds, sizeof(int) * (n_fds + j));
+ if (!f)
+ return -ENOMEM;
+
+ fds = f;
+ memcpy(fds + n_fds, d->fds, sizeof(int) * j);
+ n_fds += j;
+ break;
+ }
+
+ case KDBUS_ITEM_SECLABEL:
+ seclabel = d->str;
+ break;
+ }
+ }
+
+ if (last_was_memfd) /* memfd cannot be last part */
+ return -EBADMSG;
+
+ if (!header)
+ return -EBADMSG;
+
+ if (header_size < sizeof(struct bus_header))
+ return -EBADMSG;
+
+ /* on kdbus we only speak native endian gvariant, never dbus1
+ * marshalling or reverse endian */
+ if (header->version != 2 ||
+ header->endian != BUS_NATIVE_ENDIAN)
+ return -EPROTOTYPE;
+
+ r = bus_message_from_header(
+ bus,
+ header, header_size,
+ footer, footer_size,
+ n_bytes,
+ fds, n_fds,
+ seclabel, 0, &m);
+ if (r < 0)
+ return r;
+
+ /* The well-known names list is different from the other
+ credentials. If we asked for it, but nothing is there, this
+ means that the list of well-known names is simply empty, not
+ that we lack any data */
+
+ m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ size_t l;
+
+ l = d->size - offsetof(struct kdbus_item, data);
+
+ switch (d->type) {
+
+ case KDBUS_ITEM_PAYLOAD_OFF: {
+ size_t begin_body;
+
+ begin_body = BUS_MESSAGE_BODY_BEGIN(m);
+
+ if (idx + d->vec.size > begin_body) {
+ struct bus_body_part *part;
+
+ /* Contains body material */
+
+ part = message_append_part(m);
+ if (!part) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* A -1 offset is NUL padding. */
+ part->is_zero = d->vec.offset == ~0ULL;
+
+ if (idx >= begin_body) {
+ if (!part->is_zero)
+ part->data = (uint8_t* )k + d->vec.offset;
+ part->size = d->vec.size;
+ } else {
+ if (!part->is_zero)
+ part->data = (uint8_t*) k + d->vec.offset + (begin_body - idx);
+ part->size = d->vec.size - (begin_body - idx);
+ }
+
+ part->sealed = true;
+ }
+
+ idx += d->vec.size;
+ break;
+ }
+
+ case KDBUS_ITEM_PAYLOAD_MEMFD: {
+ struct bus_body_part *part;
+
+ if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ part = message_append_part(m);
+ if (!part) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ part->memfd = d->memfd.fd;
+ part->memfd_offset = d->memfd.start;
+ part->size = d->memfd.size;
+ part->sealed = true;
+
+ idx += d->memfd.size;
+ break;
+ }
+
+ case KDBUS_ITEM_PIDS:
+
+ /* The PID/TID might be missing, when the data
+ * is faked by a bus proxy and it lacks that
+ * information about the real client (since
+ * SO_PEERCRED is used for that). Also kernel
+ * namespacing might make some of this data
+ * unavailable when untranslatable. */
+
+ if (d->pids.pid > 0) {
+ m->creds.pid = (pid_t) d->pids.pid;
+ m->creds.mask |= SD_BUS_CREDS_PID & bus->creds_mask;
+ }
+
+ if (d->pids.tid > 0) {
+ m->creds.tid = (pid_t) d->pids.tid;
+ m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
+ }
+
+ if (d->pids.ppid > 0) {
+ m->creds.ppid = (pid_t) d->pids.ppid;
+ m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
+ } else if (d->pids.pid == 1) {
+ m->creds.ppid = 0;
+ m->creds.mask |= SD_BUS_CREDS_PPID & bus->creds_mask;
+ }
+
+ break;
+
+ case KDBUS_ITEM_CREDS:
+
+ /* EUID/SUID/FSUID/EGID/SGID/FSGID might be
+ * missing too (see above). */
+
+ if ((uid_t) d->creds.uid != UID_INVALID) {
+ m->creds.uid = (uid_t) d->creds.uid;
+ m->creds.mask |= SD_BUS_CREDS_UID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.euid != UID_INVALID) {
+ m->creds.euid = (uid_t) d->creds.euid;
+ m->creds.mask |= SD_BUS_CREDS_EUID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.suid != UID_INVALID) {
+ m->creds.suid = (uid_t) d->creds.suid;
+ m->creds.mask |= SD_BUS_CREDS_SUID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.fsuid != UID_INVALID) {
+ m->creds.fsuid = (uid_t) d->creds.fsuid;
+ m->creds.mask |= SD_BUS_CREDS_FSUID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.gid != GID_INVALID) {
+ m->creds.gid = (gid_t) d->creds.gid;
+ m->creds.mask |= SD_BUS_CREDS_GID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.egid != GID_INVALID) {
+ m->creds.egid = (gid_t) d->creds.egid;
+ m->creds.mask |= SD_BUS_CREDS_EGID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.sgid != GID_INVALID) {
+ m->creds.sgid = (gid_t) d->creds.sgid;
+ m->creds.mask |= SD_BUS_CREDS_SGID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.fsgid != GID_INVALID) {
+ m->creds.fsgid = (gid_t) d->creds.fsgid;
+ m->creds.mask |= SD_BUS_CREDS_FSGID & bus->creds_mask;
+ }
+
+ break;
+
+ case KDBUS_ITEM_TIMESTAMP:
+ message_set_timestamp(bus, m, &d->timestamp);
+ break;
+
+ case KDBUS_ITEM_PID_COMM:
+ m->creds.comm = d->str;
+ m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_TID_COMM:
+ m->creds.tid_comm = d->str;
+ m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_EXE:
+ m->creds.exe = d->str;
+ m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_CMDLINE:
+ m->creds.cmdline = d->str;
+ m->creds.cmdline_size = l;
+ m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_CGROUP:
+ m->creds.cgroup = d->str;
+ m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
+
+ r = bus_get_root_path(bus);
+ if (r < 0)
+ goto fail;
+
+ m->creds.cgroup_root = bus->cgroup_root;
+ break;
+
+ case KDBUS_ITEM_AUDIT:
+ m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
+
+ m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_CAPS:
+ if (d->caps.last_cap != cap_last_cap() ||
+ d->size - offsetof(struct kdbus_item, caps.caps) < DIV_ROUND_UP(d->caps.last_cap, 32U) * 4 * 4) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ m->creds.capability = d->caps.caps;
+ m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_DST_NAME:
+ if (!service_name_is_valid(d->str)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ destination = d->str;
+ break;
+
+ case KDBUS_ITEM_OWNED_NAME:
+ if (!service_name_is_valid(d->name.name)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ if (bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
+ char **wkn;
+ size_t n;
+
+ /* We just extend the array here, but
+ * do not allocate the strings inside
+ * of it, instead we just point to our
+ * buffer directly. */
+ n = strv_length(m->creds.well_known_names);
+ wkn = realloc(m->creds.well_known_names, (n + 2) * sizeof(char*));
+ if (!wkn) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ wkn[n] = d->name.name;
+ wkn[n+1] = NULL;
+ m->creds.well_known_names = wkn;
+
+ m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
+ }
+ break;
+
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ m->creds.description = d->str;
+ m->creds.mask |= SD_BUS_CREDS_DESCRIPTION & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_AUXGROUPS:
+
+ if (bus->creds_mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ size_t i, n;
+ gid_t *g;
+
+ n = (d->size - offsetof(struct kdbus_item, data64)) / sizeof(uint64_t);
+ g = new(gid_t, n);
+ if (!g) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ for (i = 0; i < n; i++)
+ g[i] = d->data64[i];
+
+ m->creds.supplementary_gids = g;
+ m->creds.n_supplementary_gids = n;
+ m->creds.mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
+ }
+
+ break;
+
+ case KDBUS_ITEM_FDS:
+ case KDBUS_ITEM_SECLABEL:
+ case KDBUS_ITEM_BLOOM_FILTER:
+ break;
+
+ default:
+ log_debug("Got unknown field from kernel %llu", d->type);
+ }
+ }
+
+ /* If we requested the list of well-known names to be appended
+ * and the sender had none no item for it will be
+ * attached. However, this does *not* mean that the kernel
+ * didn't want to provide this information to us. Hence, let's
+ * explicitly mark this information as available if it was
+ * requested. */
+ m->creds.mask |= bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
+
+ r = bus_message_parse_fields(m);
+ if (r < 0)
+ goto fail;
+
+ /* Refuse messages if kdbus and dbus1 cookie doesn't match up */
+ if ((uint64_t) m->header->dbus2.cookie != k->cookie) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse messages where the reply flag doesn't match up */
+ if (!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) != !!(k->flags & KDBUS_MSG_EXPECT_REPLY)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse reply messages where the reply cookie doesn't match up */
+ if ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) && m->reply_cookie != k->cookie_reply) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse messages where the autostart flag doesn't match up */
+ if (!(m->header->flags & BUS_MESSAGE_NO_AUTO_START) != !(k->flags & KDBUS_MSG_NO_AUTO_START)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Override information from the user header with data from the kernel */
+ if (k->src_id == KDBUS_SRC_ID_KERNEL)
+ bus_message_set_sender_driver(bus, m);
+ else {
- xsprintf(m->sender_buffer, ":1.%llu", k->src_id);
- m->sender = m->creds.unique_name = m->sender_buffer;
++ //xsprintf(m->sender_buffer, ":1.%llu", k->src_id);
++ //m->sender = m->creds.unique_name = m->sender_buffer;
+ }
+
+ if (destination)
+ m->destination = destination;
+ else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
+ m->destination = NULL;
+ else if (k->dst_id == KDBUS_DST_ID_NAME)
+ m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
+ else {
- xsprintf(m->destination_buffer, ":1.%llu", k->dst_id);
- m->destination = m->destination_buffer;
++ //xsprintf(m->destination_buffer, ":1.%llu", k->dst_id);
++ //m->destination = m->destination_buffer;
+ }
+
+ /* We take possession of the kmsg struct now */
+ m->kdbus = k;
+ m->release_kdbus = true;
+ m->free_fds = true;
+ fds = NULL;
+
+ bus->rqueue[bus->rqueue_size++] = m;
+
+ return 1;
+
+fail:
+ unset_memfds(m);
+ sd_bus_message_unref(m);
+
+ return r;
+}
+
+int bus_kernel_take_fd(sd_bus *b) {
+ struct kdbus_bloom_parameter *bloom = NULL;
+ struct kdbus_item *items, *item;
+ struct kdbus_cmd_hello *hello;
+ _cleanup_free_ char *g = NULL;
+ const char *name;
+ size_t l = 0, m = 0, sz;
+ int r;
+
+ assert(b);
+
+ if (b->is_server)
+ return -EINVAL;
+
+ b->use_memfd = 1;
+
+ if (b->description) {
+ g = bus_label_escape(b->description);
+ if (!g)
+ return -ENOMEM;
+
+ name = g;
+ } else {
+ char pr[17] = {};
+
+ /* If no name is explicitly set, we'll include a hint
+ * indicating the library implementation, a hint which
+ * kind of bus this is and the thread name */
+
+ assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
+
+ if (isempty(pr)) {
+ name = b->is_system ? "sd-system" :
+ b->is_user ? "sd-user" : "sd";
+ } else {
+ _cleanup_free_ char *e = NULL;
+
+ e = bus_label_escape(pr);
+ if (!e)
+ return -ENOMEM;
+
+ g = strappend(b->is_system ? "sd-system-" :
+ b->is_user ? "sd-user-" : "sd-",
+ e);
+ if (!g)
+ return -ENOMEM;
+
+ name = g;
+ }
+
+ b->description = bus_label_unescape(name);
+ if (!b->description)
+ return -ENOMEM;
+ }
+
+ m = strlen(name);
+
+ sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
+ ALIGN8(offsetof(struct kdbus_item, str) + m + 1);
+
+ if (b->fake_creds_valid)
+ sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds));
+
+ if (b->fake_pids_valid)
+ sz += ALIGN8(offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids));
+
+ if (b->fake_label) {
+ l = strlen(b->fake_label);
+ sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
+ }
+
+ hello = alloca0_align(sz, 8);
+ hello->size = sz;
- hello->flags = b->hello_flags;
++ //hello->flags = b->hello_flags;
+ hello->attach_flags_send = _KDBUS_ATTACH_ANY;
- hello->attach_flags_recv = b->attach_flags;
++ //hello->attach_flags_recv = b->attach_flags;
+ hello->pool_size = KDBUS_POOL_SIZE;
+
+ item = hello->items;
+
+ item->size = offsetof(struct kdbus_item, str) + m + 1;
+ item->type = KDBUS_ITEM_CONN_DESCRIPTION;
+ memcpy(item->str, name, m + 1);
+ item = KDBUS_ITEM_NEXT(item);
+
+ if (b->fake_creds_valid) {
+ item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
+ item->type = KDBUS_ITEM_CREDS;
+ item->creds = b->fake_creds;
+
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
+ if (b->fake_pids_valid) {
+ item->size = offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids);
+ item->type = KDBUS_ITEM_PIDS;
+ item->pids = b->fake_pids;
+
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
+ if (b->fake_label) {
+ item->size = offsetof(struct kdbus_item, str) + l + 1;
+ item->type = KDBUS_ITEM_SECLABEL;
+ memcpy(item->str, b->fake_label, l+1);
+ }
+
+ r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
+ if (r < 0) {
+ if (errno == ENOTTY)
+ /* If the ioctl is not supported we assume that the
+ * API version changed in a major incompatible way,
+ * let's indicate an API incompatibility in this
+ * case. */
+ return -ESOCKTNOSUPPORT;
+
+ return -errno;
+ }
+
+ if (!b->kdbus_buffer) {
+ b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
+ if (b->kdbus_buffer == MAP_FAILED) {
+ b->kdbus_buffer = NULL;
+ r = -errno;
+ goto fail;
+ }
+ }
+
+ /* The higher 32bit of the bus_flags fields are considered
+ * 'incompatible flags'. Refuse them all for now. */
+ if (hello->bus_flags > 0xFFFFFFFFULL) {
+ r = -ESOCKTNOSUPPORT;
+ goto fail;
+ }
+
+ /* extract bloom parameters from items */
+ items = (void*)((uint8_t*)b->kdbus_buffer + hello->offset);
+ KDBUS_FOREACH(item, items, hello->items_size) {
+ switch (item->type) {
+ case KDBUS_ITEM_BLOOM_PARAMETER:
+ bloom = &item->bloom_parameter;
+ break;
+ }
+ }
+
- if (!bloom || !bloom_validate_parameters((size_t) bloom->size, (unsigned) bloom->n_hash)) {
- r = -EOPNOTSUPP;
- goto fail;
- }
++ //if (!bloom || !bloom_validate_parameters((size_t) bloom->size, (unsigned) bloom->n_hash)) {
++ //r = -EOPNOTSUPP;
++ //goto fail;
++ //}
+
+ b->bloom_size = (size_t) bloom->size;
+ b->bloom_n_hash = (unsigned) bloom->n_hash;
+
+ if (asprintf(&b->unique_name, ":1.%llu", hello->id) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ b->unique_id = hello->id;
+
+ b->is_kernel = true;
+ b->bus_client = true;
+ b->can_fds = !!(hello->flags & KDBUS_HELLO_ACCEPT_FD);
+ b->message_version = 2;
+ b->message_endian = BUS_NATIVE_ENDIAN;
+
+ /* the kernel told us the UUID of the underlying bus */
+ memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
+
+ /* free returned items */
+ (void) bus_kernel_cmd_free(b, hello->offset);
+ return bus_start_running(b);
+
+fail:
+ (void) bus_kernel_cmd_free(b, hello->offset);
+ return r;
+}
+
+int bus_kernel_connect(sd_bus *b) {
+ assert(b);
+ assert(b->input_fd < 0);
+ assert(b->output_fd < 0);
+ assert(b->kernel);
+
+ if (b->is_server)
+ return -EINVAL;
+
+ b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (b->input_fd < 0)
+ return -errno;
+
+ b->output_fd = b->input_fd;
+
+ return bus_kernel_take_fd(b);
+}
+
+int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset) {
+ struct kdbus_cmd_free cmd = {
+ .size = sizeof(cmd),
+ .offset = offset,
+ };
+ int r;
+
+ assert(bus);
+ assert(bus->is_kernel);
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
+ struct kdbus_item *d;
+
+ assert(bus);
+ assert(k);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ if (d->type == KDBUS_ITEM_FDS)
+ close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
+ else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
+ safe_close(d->memfd.fd);
+ }
+
+ bus_kernel_cmd_free(bus, (uint8_t*) k - (uint8_t*) bus->kdbus_buffer);
+}
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) {
+ struct kdbus_cmd_send cmd = { };
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(bus->state == BUS_RUNNING);
+
+ /* If we can't deliver, we want room for the error message */
+ r = bus_rqueue_make_room(bus);
+ if (r < 0)
+ return r;
+
+ r = bus_message_setup_kmsg(bus, m);
+ if (r < 0)
+ return r;
+
+ cmd.size = sizeof(cmd);
+ cmd.msg_address = (uintptr_t)m->kdbus;
+
+ /* If this is a synchronous method call, then let's tell the
+ * kernel, so that it can pass CPU time/scheduling to the
+ * destination for the time, if it wants to. If we
+ * synchronously wait for the result anyway, we won't need CPU
+ * anyway. */
+ if (hint_sync_call) {
+ m->kdbus->flags |= KDBUS_MSG_EXPECT_REPLY;
+ cmd.flags |= KDBUS_SEND_SYNC_REPLY;
+ }
+
+ r = ioctl(bus->output_fd, KDBUS_CMD_SEND, &cmd);
+ if (r < 0) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *reply;
+
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
+ else if (errno == ENXIO || errno == ESRCH) {
+
+ /* ENXIO: unique name not known
+ * ESRCH: well-known name not known */
+
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
+ else {
+ log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
+ return 0;
+ }
+
+ } else if (errno == EADDRNOTAVAIL) {
+
+ /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
+
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
+ else {
+ log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
+ return 0;
+ }
+ } else
+ return -errno;
+
+ r = bus_message_new_synthetic_error(
+ bus,
+ BUS_MESSAGE_COOKIE(m),
+ &error,
+ &reply);
+
+ if (r < 0)
+ return r;
+
+ r = bus_seal_synthetic_message(bus, reply);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = reply;
+
+ } else if (hint_sync_call) {
+ struct kdbus_msg *k;
+
+ k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + cmd.reply.offset);
+ assert(k);
+
+ if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
+
+ r = bus_kernel_make_message(bus, k);
+ if (r < 0) {
+ close_kdbus_msg(bus, k);
+
+ /* Anybody can send us invalid messages, let's just drop them. */
+ if (r == -EBADMSG || r == -EPROTOTYPE)
+ log_debug_errno(r, "Ignoring invalid synchronous reply: %m");
+ else
+ return r;
+ }
+ } else {
+ log_debug("Ignoring message with unknown payload type %llu.", k->payload_type);
+ close_kdbus_msg(bus, k);
+ }
+ }
+
+ return 1;
+}
+
+static int push_name_owner_changed(
+ sd_bus *bus,
+ const char *name,
+ const char *old_owner,
+ const char *new_owner,
+ const struct kdbus_timestamp *ts) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+
+ r = sd_bus_message_new_signal(
+ bus,
+ &m,
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
+ if (r < 0)
+ return r;
+
+ bus_message_set_sender_driver(bus, m);
+ message_set_timestamp(bus, m, ts);
+
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
+
+ return 1;
+}
+
+static int translate_name_change(
+ sd_bus *bus,
+ const struct kdbus_msg *k,
+ const struct kdbus_item *d,
+ const struct kdbus_timestamp *ts) {
+
+ char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
+ old_owner[0] = 0;
+ else
+ sprintf(old_owner, ":1.%llu", d->name_change.old_id.id);
+
+ if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
+
+ if (isempty(old_owner))
+ return 0;
+
+ new_owner[0] = 0;
+ } else
+ sprintf(new_owner, ":1.%llu", d->name_change.new_id.id);
+
+ return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner, ts);
+}
+
+static int translate_id_change(
+ sd_bus *bus,
+ const struct kdbus_msg *k,
+ const struct kdbus_item *d,
+ const struct kdbus_timestamp *ts) {
+
+ char owner[UNIQUE_NAME_MAX];
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ sprintf(owner, ":1.%llu", d->id_change.id);
+
+ return push_name_owner_changed(
+ bus, owner,
+ d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
+ d->type == KDBUS_ITEM_ID_ADD ? owner : NULL,
+ ts);
+}
+
+static int translate_reply(
+ sd_bus *bus,
+ const struct kdbus_msg *k,
+ const struct kdbus_item *d,
+ const struct kdbus_timestamp *ts) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ int r;
+
+ assert(bus);
+ assert(k);
+ assert(d);
+
+ r = bus_message_new_synthetic_error(
+ bus,
+ k->cookie_reply,
+ d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
+ &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
+ &m);
+ if (r < 0)
+ return r;
+
+ message_set_timestamp(bus, m, ts);
+
+ r = bus_seal_synthetic_message(bus, m);
+ if (r < 0)
+ return r;
+
+ bus->rqueue[bus->rqueue_size++] = m;
+ m = NULL;
+
+ return 1;
+}
+
+static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
+ static int (* const translate[])(sd_bus *bus, const struct kdbus_msg *k, const struct kdbus_item *d, const struct kdbus_timestamp *ts) = {
+ [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+ [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
+
+ [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+ [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
+
+ [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
+ };
+
+ struct kdbus_item *d, *found = NULL;
+ struct kdbus_timestamp *ts = NULL;
+
+ assert(bus);
+ assert(k);
+ assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
+
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ if (d->type == KDBUS_ITEM_TIMESTAMP)
+ ts = &d->timestamp;
+ else if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
+ if (found)
+ return -EBADMSG;
+ found = d;
+ } else
+ log_debug("Got unknown field from kernel %llu", d->type);
+ }
+
+ if (!found) {
+ log_debug("Didn't find a kernel message to translate.");
+ return 0;
+ }
+
+ return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found, ts);
+}
+
+int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
+ struct kdbus_cmd_recv recv = { .size = sizeof(recv) };
+ struct kdbus_msg *k;
+ int r;
+
+ assert(bus);
+
+ r = bus_rqueue_make_room(bus);
+ if (r < 0)
+ return r;
+
+ if (hint_priority) {
+ recv.flags |= KDBUS_RECV_USE_PRIORITY;
+ recv.priority = priority;
+ }
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_RECV, &recv);
+ if (recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS)
+ log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs);
+ if (r < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ return -errno;
+ }
+
+ k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.msg.offset);
+ if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
+ r = bus_kernel_make_message(bus, k);
+
+ /* Anybody can send us invalid messages, let's just drop them. */
+ if (r == -EBADMSG || r == -EPROTOTYPE) {
+ log_debug_errno(r, "Ignoring invalid message: %m");
+ r = 0;
+ }
+
+ if (r <= 0)
+ close_kdbus_msg(bus, k);
+ } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL) {
+ r = bus_kernel_translate_message(bus, k);
+ close_kdbus_msg(bus, k);
+ } else {
+ log_debug("Ignoring message with unknown payload type %llu.", k->payload_type);
+ r = 0;
+ close_kdbus_msg(bus, k);
+ }
+
+ return r < 0 ? r : 1;
+}
+
+int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) {
+ struct memfd_cache *c;
+ int fd;
+
+ assert(address);
+ assert(mapped);
+ assert(allocated);
+
+ if (!bus || !bus->is_kernel)
+ return -EOPNOTSUPP;
+
+ assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
+
+ if (bus->n_memfd_cache <= 0) {
+ int r;
+
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
+
+ r = memfd_new(bus->description);
+ if (r < 0)
+ return r;
+
+ *address = NULL;
+ *mapped = 0;
+ *allocated = 0;
+ return r;
+ }
+
+ c = &bus->memfd_cache[--bus->n_memfd_cache];
+
+ assert(c->fd >= 0);
+ assert(c->mapped == 0 || c->address);
+
+ *address = c->address;
+ *mapped = c->mapped;
+ *allocated = c->allocated;
+ fd = c->fd;
+
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
+
+ return fd;
+}
+
+static void close_and_munmap(int fd, void *address, size_t size) {
if (size > 0)
assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
for (i = 0; i < b->n_memfd_cache; i++)
close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
}
- uint64_t attach_flags_to_kdbus(uint64_t mask) {
- uint64_t m = 0;
-
- if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
- SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID))
- m |= KDBUS_ATTACH_CREDS;
-
- if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID))
- m |= KDBUS_ATTACH_PIDS;
-
- if (mask & SD_BUS_CREDS_COMM)
- m |= KDBUS_ATTACH_PID_COMM;
-
- if (mask & SD_BUS_CREDS_TID_COMM)
- m |= KDBUS_ATTACH_TID_COMM;
-
- if (mask & SD_BUS_CREDS_EXE)
- m |= KDBUS_ATTACH_EXE;
-
- if (mask & SD_BUS_CREDS_CMDLINE)
- m |= KDBUS_ATTACH_CMDLINE;
-
- if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
- m |= KDBUS_ATTACH_CGROUP;
-
- if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
- m |= KDBUS_ATTACH_CAPS;
-
- if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
- m |= KDBUS_ATTACH_SECLABEL;
-
- if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
- m |= KDBUS_ATTACH_AUDIT;
-
- if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
- m |= KDBUS_ATTACH_NAMES;
-
- if (mask & SD_BUS_CREDS_DESCRIPTION)
- m |= KDBUS_ATTACH_CONN_DESCRIPTION;
-
- if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS)
- m |= KDBUS_ATTACH_AUXGROUPS;
-
- return m;
- }
-
+
+uint64_t request_name_flags_to_kdbus(uint64_t flags) {
+ uint64_t f = 0;
+
+ if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
+ f |= KDBUS_NAME_ALLOW_REPLACEMENT;
+
+ if (flags & SD_BUS_NAME_REPLACE_EXISTING)
+ f |= KDBUS_NAME_REPLACE_EXISTING;
+
+ if (flags & SD_BUS_NAME_QUEUE)
+ f |= KDBUS_NAME_QUEUE;
+
+ return f;
+}
+
- n->bloom_parameter.size = DEFAULT_BLOOM_SIZE;
- n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH;
+int bus_kernel_create_bus(const char *name, bool world, char **s) {
+ struct kdbus_cmd *make;
+ struct kdbus_item *n;
+ size_t l;
+ int fd;
+
+ assert(name);
+ assert(s);
+
+ fd = open("/sys/fs/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ l = strlen(name);
+ make = alloca0_align(offsetof(struct kdbus_cmd, items) +
+ ALIGN8(offsetof(struct kdbus_item, bloom_parameter) + sizeof(struct kdbus_bloom_parameter)) +
+ ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)) +
+ ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1),
+ 8);
+
+ make->size = offsetof(struct kdbus_cmd, items);
+
+ /* Set the bloom parameters */
+ n = make->items;
+ n->size = offsetof(struct kdbus_item, bloom_parameter) +
+ sizeof(struct kdbus_bloom_parameter);
+ n->type = KDBUS_ITEM_BLOOM_PARAMETER;
- assert_cc(DEFAULT_BLOOM_SIZE > 0);
- assert_cc(DEFAULT_BLOOM_N_HASH > 0);
++ //n->bloom_parameter.size = DEFAULT_BLOOM_SIZE;
++ //n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH;
+
- n->data64[0] = bus->attach_flags;
++ //assert_cc(DEFAULT_BLOOM_SIZE > 0);
++ //assert_cc(DEFAULT_BLOOM_N_HASH > 0);
+
+ make->size += ALIGN8(n->size);
+
+ /* Provide all metadata via bus-owner queries */
+ n = KDBUS_ITEM_NEXT(n);
+ n->type = KDBUS_ITEM_ATTACH_FLAGS_SEND;
+ n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
+ n->data64[0] = _KDBUS_ATTACH_ANY;
+ make->size += ALIGN8(n->size);
+
+ /* Set the a good name */
+ n = KDBUS_ITEM_NEXT(n);
+ sprintf(n->str, UID_FMT "-%s", getuid(), name);
+ n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
+ n->type = KDBUS_ITEM_MAKE_NAME;
+ make->size += ALIGN8(n->size);
+
+ make->flags = world ? KDBUS_MAKE_ACCESS_WORLD : 0;
+
+ if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
+ safe_close(fd);
+
+ /* Major API change? then the ioctls got shuffled around. */
+ if (errno == ENOTTY)
+ return -ESOCKTNOSUPPORT;
+
+ return -errno;
+ }
+
+ if (s) {
+ char *p;
+
+ p = strjoin("/sys/fs/kdbus/", n->str, "/bus");
+ if (!p) {
+ safe_close(fd);
+ return -ENOMEM;
+ }
+
+ *s = p;
+ }
+
+ return fd;
+}
+
+int bus_kernel_open_bus_fd(const char *bus, char **path) {
+ char *p;
+ int fd;
+ size_t len;
+
+ assert(bus);
+
+ len = strlen("/sys/fs/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1;
+
+ if (path) {
+ p = new(char, len);
+ if (!p)
+ return -ENOMEM;
+ } else
+ p = newa(char, len);
+
+ sprintf(p, "/sys/fs/kdbus/" UID_FMT "-%s/bus", getuid(), bus);
+
+ fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0) {
+ if (path)
+ free(p);
+
+ return -errno;
+ }
+
+ if (path)
+ *path = p;
+
+ return fd;
+}
+
+int bus_kernel_try_close(sd_bus *bus) {
+ struct kdbus_cmd byebye = { .size = sizeof(byebye) };
+
+ assert(bus);
+ assert(bus->is_kernel);
+
+ if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE, &byebye) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bus_kernel_drop_one(int fd) {
+ struct kdbus_cmd_recv recv = {
+ .size = sizeof(recv),
+ .flags = KDBUS_RECV_DROP,
+ };
+
+ assert(fd >= 0);
+
+ if (ioctl(fd, KDBUS_CMD_RECV, &recv) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bus_kernel_realize_attach_flags(sd_bus *bus) {
+ struct kdbus_cmd *update;
+ struct kdbus_item *n;
+
+ assert(bus);
+ assert(bus->is_kernel);
+
+ update = alloca0_align(offsetof(struct kdbus_cmd, items) +
+ ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)),
+ 8);
+
+ n = update->items;
+ n->type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
+ n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
++ //n->data64[0] = bus->attach_flags;
+
+ update->size =
+ offsetof(struct kdbus_cmd, items) +
+ ALIGN8(n->size);
+
+ if (ioctl(bus->input_fd, KDBUS_CMD_UPDATE, update) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bus_kernel_get_bus_name(sd_bus *bus, char **name) {
+ struct kdbus_cmd_info cmd = {
+ .size = sizeof(struct kdbus_cmd_info),
+ };
+ struct kdbus_info *info;
+ struct kdbus_item *item;
+ char *n = NULL;
+ int r;
+
+ assert(bus);
+ assert(name);
+ assert(bus->is_kernel);
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
+ if (r < 0)
+ return -errno;
+
+ info = (struct kdbus_info*) ((uint8_t*) bus->kdbus_buffer + cmd.offset);
+
+ KDBUS_ITEM_FOREACH(item, info, items)
+ if (item->type == KDBUS_ITEM_MAKE_NAME) {
+ r = free_and_strdup(&n, item->str);
+ break;
+ }
+
+ bus_kernel_cmd_free(bus, cmd.offset);
+
+ if (r < 0)
+ return r;
+ if (!n)
+ return -EIO;
+
+ *name = n;
+ return 0;
+}
size_t allocated;
};
-void close_and_munmap(int fd, void *address, size_t size);
-void bus_flush_memfd(sd_bus *bus);
+int bus_kernel_connect(sd_bus *b);
+int bus_kernel_take_fd(sd_bus *b);
+
+int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call);
+int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority);
+
+int bus_kernel_open_bus_fd(const char *bus, char **path);
+
+int bus_kernel_create_bus(const char *name, bool world, char **s);
+int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **path);
+
+int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated);
+void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated);
+
+void bus_kernel_flush_memfd(sd_bus *bus);
+
+int bus_kernel_parse_unique_name(const char *s, uint64_t *id);
+
+uint64_t request_name_flags_to_kdbus(uint64_t sd_bus_flags);
- uint64_t attach_flags_to_kdbus(uint64_t sd_bus_flags);
+
+int bus_kernel_try_close(sd_bus *bus);
+
+int bus_kernel_drop_one(int fd);
+
+int bus_kernel_realize_attach_flags(sd_bus *bus);
+
+int bus_kernel_get_bus_name(sd_bus *bus, char **name);
+
+int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset);
case BUS_MATCH_CALLBACK:
if (slot->match_added)
- bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
- (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
++ (void) bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
+
+ if (slot->match_callback.install_slot) {
+ bus_slot_disconnect(slot->match_callback.install_slot);
+ slot->match_callback.install_slot = sd_bus_slot_unref(slot->match_callback.install_slot);
+ }
slot->bus->match_callbacks_modified = true;
bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
assert(b);
/* Increase the buffers to 8 MB */
- fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
- fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
+ (void) fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
+ (void) fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
+ b->is_kernel = false;
b->message_version = 1;
b->message_endian = 0;
}
if (b->default_bus_ptr)
*b->default_bus_ptr = NULL;
- bus_close_fds(b);
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
+ if (b->kdbus_buffer)
+ munmap(b->kdbus_buffer, KDBUS_POOL_SIZE);
+
free(b->label);
+ free(b->groups);
free(b->rbuffer);
free(b->unique_name);
free(b->auth_buffer);
free(b->address);
+ free(b->kernel);
free(b->machine);
+ free(b->fake_label);
free(b->cgroup_root);
free(b->description);
+ free(b->patch_sender);
free(b->exec_path);
strv_free(b->exec_argv);
}
int bus_start_running(sd_bus *bus) {
+ struct reply_callback *c;
+ Iterator i;
+ usec_t n;
+ int r;
+
assert(bus);
+ assert(bus->state < BUS_HELLO);
+
+ /* We start all method call timeouts when we enter BUS_HELLO or BUS_RUNNING mode. At this point let's convert
+ * all relative to absolute timestamps. Note that we do not reshuffle the reply callback priority queue since
+ * adding a fixed value to all entries should not alter the internal order. */
+
+ n = now(CLOCK_MONOTONIC);
+ ORDERED_HASHMAP_FOREACH(c, bus->reply_callbacks, i) {
+ if (c->timeout_usec == 0)
+ continue;
+
+ c->timeout_usec = usec_add(n, c->timeout_usec);
+ }
- if (bus->bus_client) {
+ if (bus->bus_client && !bus->is_kernel) {
- bus->state = BUS_HELLO;
+ bus_set_state(bus, BUS_HELLO);
return 1;
}
assert(b);
for (;;) {
- bus_close_fds(b);
+ bool skipped = false;
+
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
- /* If you provide multiple different bus-addresses, we
- * try all of them in order and use the first one that
- * succeeds. */
+ /*
+ * Usually, if you provide multiple different bus-addresses, we
+ * try all of them in order. We use the first one that
+ * succeeds. However, if you mix kernel and unix addresses, we
+ * never try unix-addresses if a previous kernel address was
+ * tried and kdbus was available. This is required to prevent
+ * clients to fallback to the bus-proxy if kdbus is available
+ * but failed (eg., too many connections).
+ */
if (b->exec_path)
r = bus_socket_exec(b);
- else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC)
- r = bus_container_connect_socket(b);
- else if (b->sockaddr.sa.sa_family != AF_UNSPEC)
- r = bus_socket_connect(b);
- else
- goto next;
+ else if ((b->nspid > 0 || b->machine) && b->kernel) {
+ r = bus_container_connect_kernel(b);
+ if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT))
+ container_kdbus_available = true;
+
+ } else if ((b->nspid > 0 || b->machine) && b->sockaddr.sa.sa_family != AF_UNSPEC) {
+ if (!container_kdbus_available)
+ r = bus_container_connect_socket(b);
+ else
+ skipped = true;
- if (r >= 0) {
- int q;
+ } else if (b->kernel) {
+ r = bus_kernel_connect(b);
+ if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT))
+ kdbus_available = true;
- q = bus_attach_io_events(b);
- if (q < 0)
- return q;
+ } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
+ if (!kdbus_available)
+ r = bus_socket_connect(b);
+ else
+ skipped = true;
+ } else
+ skipped = true;
- q = bus_attach_inotify_event(b);
- if (q < 0)
- return q;
+ if (!skipped) {
+ if (r >= 0) {
- r = attach_io_events(b);
- if (r >= 0)
- return r;
++ int q;
+
- return r;
- }
++ q = bus_attach_io_events(b);
++ if (q < 0)
++ return q;
+
- b->last_connect_error = -r;
++ q = bus_attach_inotify_event(b);
++ if (q < 0)
++ return q;
++
++ return r;
+ }
+
+ b->last_connect_error = -r;
+ }
- next:
r = bus_parse_next_address(b);
if (r < 0)
return r;
if (e)
return sd_bus_set_address(b, e);
+ r = cg_pid_get_owner_uid(0, &uid);
+ if (r < 0)
+ uid = getuid();
+
e = secure_getenv("XDG_RUNTIME_DIR");
- if (!e)
- return -ENOENT;
+ if (e) {
+ _cleanup_free_ char *ee = NULL;
- ee = bus_address_escape(e);
- if (!ee)
- return -ENOMEM;
+ ee = bus_address_escape(e);
+ if (!ee)
+ return -ENOMEM;
- (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee);
- if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, ee) < 0)
- return -ENOMEM;
++ (void) asprintf(&b->address, DEFAULT_USER_BUS_ADDRESS_FMT, uid, ee);
+ } else
+ (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid);
- b->address = s;
- s = NULL;
+ if (!b->address)
+ return -ENOMEM;
return 0;
}
* the bus object and the bus may be freed */
bus_reset_queues(bus);
- bus_close_io_fds(bus);
+ if (!bus->is_kernel)
- bus_close_fds(bus);
++ bus_close_io_fds(bus);
+
+ /* We'll leave the fd open in case this is a kernel bus, since
+ * there might still be memblocks around that reference this
+ * bus, and they might need to invoke the KDBUS_CMD_FREE
+ * ioctl on the fd when they are freed. */
++
+ bus_close_inotify_fd(bus);
}
_public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
assert(bus);
assert(m);
- if (bus->is_kernel)
- r = bus_kernel_write_message(bus, m, hint_sync_call);
- else
- r = bus_socket_write_message(bus, m, idx);
++ //if (bus->is_kernel)
++ //r = bus_kernel_write_message(bus, m, hint_sync_call);
++ //else
+ r = bus_socket_write_message(bus, m, idx);
+
if (r <= 0)
return r;
- if (*idx >= BUS_MESSAGE_SIZE(m))
+ if (bus->is_kernel || *idx >= BUS_MESSAGE_SIZE(m))
- log_debug("Sent message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error-name=%s error-message=%s",
+ log_debug("Sent message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s",
bus_message_type_to_string(m->header->type),
strna(sd_bus_message_get_sender(m)),
strna(sd_bus_message_get_destination(m)),
bus = m->bus;
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
++ //assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
bus = m->bus;
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
++ //assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
bus = m->bus;
bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
- bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error);
++ //bus_assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS, error);
if (!BUS_IS_OPEN(bus->state)) {
r = -ENOTCONN;
if (!IN_SET(m->header->type, SD_BUS_MESSAGE_METHOD_RETURN, SD_BUS_MESSAGE_METHOD_ERROR))
return 0;
- if (bus->is_kernel && (bus->hello_flags & KDBUS_HELLO_MONITOR))
- return 0;
++ //if (bus->is_kernel && (bus->hello_flags & KDBUS_HELLO_MONITOR))
++ //return 0;
+
if (m->destination && bus->unique_name && !streq_ptr(m->destination, bus->unique_name))
return 0;
}
s->match_callback.callback = callback;
+ s->match_callback.install_callback = install_callback;
+ s->match_callback.cookie = ++bus->match_cookie;
if (bus->bus_client) {
enum bus_match_scope scope;
scope = bus_match_get_scope(components, n_components);
- /* Do not install server-side matches for matches
- * against the local service, interface or bus
- * path. */
+ /* Do not install server-side matches for matches against the local service, interface or bus path. */
if (scope != BUS_MATCH_LOCAL) {
- /* We store the original match string, so that we can use it to remove the match again. */
+ if (!bus->is_kernel) {
- /* When this is not a kernel transport, we
- * store the original match string, so that we
- * can use it to remove the match again */
++ /* When this is not a kernel transport we store the original match string, so that we can use it to remove the match again. */
- s->match_callback.match_string = strdup(match);
- if (!s->match_callback.match_string) {
- r = -ENOMEM;
- goto finish;
+ s->match_callback.match_string = strdup(match);
+ if (!s->match_callback.match_string) {
+ r = -ENOMEM;
+ goto finish;
+ }
}
- r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components, s->match_callback.cookie);
+ if (asynchronous)
+ r = bus_add_match_internal_async(bus,
+ &s->match_callback.install_slot,
+ s->match_callback.match_string,
+ add_match_callback,
+ s);
+ else
- r = bus_add_match_internal(bus, s->match_callback.match_string);
++ r = bus_add_match_internal(bus, s->match_callback.match_string, s->match_callback.cookie);
if (r < 0)
goto finish;
}
_public_ int sd_bus_try_close(sd_bus *bus) {
+ int r;
+
assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(!bus_pid_changed(bus), -ECHILD);
- return -EOPNOTSUPP;
+ if (!bus->is_kernel)
+ return -EOPNOTSUPP;
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
+ if (bus->rqueue_size > 0)
+ return -EBUSY;
+
+ if (bus->wqueue_size > 0)
+ return -EBUSY;
+
+ r = bus_kernel_try_close(bus);
+ if (r < 0)
+ return r;
+
+ sd_bus_close(bus);
+ return 0;
}
_public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
}
_public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
+ int r;
+
assert_return(bus, -EINVAL);
+ assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(scope, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
#include "bus-util.h"
#include "def.h"
#include "fd-util.h"
++#include "process-util.h"
#include "time-util.h"
#include "util.h"
--- /dev/null
+/***
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
++#include "process-util.h"
+#include "util.h"
+
+static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+ int *found = userdata;
+
+ *found = 1;
+
+ return 0;
+}
+
+static void test_one(
+ const char *path,
+ const char *interface,
+ const char *member,
+ bool as_list,
+ const char *arg0,
+ const char *match,
+ bool good) {
+
+ _cleanup_close_ int bus_ref = -1;
+ _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ sd_bus *a, *b;
+ int r, found = 0;
+
+ 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)
+ exit(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);
+
+ log_debug("match");
+ r = sd_bus_add_match(b, NULL, match, test_match, &found);
+ assert_se(r >= 0);
+
+ log_debug("signal");
+
+ if (as_list)
+ r = sd_bus_emit_signal(a, path, interface, member, "as", 1, arg0);
+ else
+ r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
+ assert_se(r >= 0);
+
+ r = sd_bus_process(b, &m);
+ assert_se(r >= 0 && good == !!found);
+
+ sd_bus_unref(a);
+ sd_bus_unref(b);
+}
+
+int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/tuut'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "interface='waldo.com'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Piep'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0has='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
+
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/quux'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/quux'", false);
+ test_one("/", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
+
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo/'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/'", true);
+
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/bar/waldo", "arg0path='/foo/'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo", "arg0path='/foo/bar/waldo'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "/foo/", "arg0path='/foo/bar/waldo'", true);
+
+ return 0;
+}
--- /dev/null
+/***
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+
+#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
++#include "process-util.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+ _cleanup_close_ int bus_ref = -1;
+ _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *bname = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *ua = NULL, *ub = NULL, *the_string = NULL;
+ sd_bus *a, *b;
+ int r, pipe_fds[2];
+ const char *nn;
+
+ 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_description(a, "a");
+ 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);
+
+ assert_se(sd_bus_negotiate_timestamp(a, 1) >= 0);
+ assert_se(sd_bus_negotiate_creds(a, true, _SD_BUS_CREDS_ALL) >= 0);
+
+ assert_se(sd_bus_negotiate_timestamp(b, 0) >= 0);
+ assert_se(sd_bus_negotiate_creds(b, true, 0) >= 0);
+
+ r = sd_bus_start(a);
+ assert_se(r >= 0);
+
+ r = sd_bus_start(b);
+ assert_se(r >= 0);
+
+ assert_se(sd_bus_negotiate_timestamp(b, 1) >= 0);
+ assert_se(sd_bus_negotiate_creds(b, true, _SD_BUS_CREDS_ALL) >= 0);
+
+ r = sd_bus_get_unique_name(a, &ua);
+ assert_se(r >= 0);
+ printf("unique a: %s\n", ua);
+
+ r = sd_bus_get_description(a, &nn);
+ assert_se(r >= 0);
+ printf("name of a: %s\n", nn);
+
+ r = sd_bus_get_unique_name(b, &ub);
+ assert_se(r >= 0);
+ printf("unique b: %s\n", ub);
+
+ r = sd_bus_get_description(b, &nn);
+ assert_se(r >= 0);
+ printf("name of b: %s\n", nn);
+
+ assert_se(bus_kernel_get_bus_name(b, &bname) >= 0);
+ assert_se(endswith(bname, name));
+
+ r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
+ assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
+ assert_se(r == -EHOSTUNREACH);
+
+ r = sd_bus_add_match(b, NULL, "interface='waldo.com',member='Piep'", NULL, NULL);
+ assert_se(r >= 0);
+
+ r = sd_bus_emit_signal(a, "/foo/bar/waldo", "waldo.com", "Piep", "sss", "I am a string", "/this/is/a/path", "and.this.a.domain.name");
+ assert_se(r >= 0);
+
+ r = sd_bus_try_close(b);
+ assert_se(r == -EBUSY);
+
+ r = sd_bus_process_priority(b, -10, &m);
+ assert_se(r == 0);
+
+ r = sd_bus_process(b, &m);
+ assert_se(r > 0);
+ assert_se(m);
+
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
+ assert_se(sd_bus_message_rewind(m, true) >= 0);
+
+ r = sd_bus_message_read(m, "s", &the_string);
+ assert_se(r >= 0);
+ assert_se(streq(the_string, "I am a string"));
+
+ sd_bus_message_unref(m);
+ m = NULL;
+
+ r = sd_bus_request_name(a, "net.x0pointer.foobar", 0);
+ assert_se(r >= 0);
+
+ r = sd_bus_message_new_method_call(b, &m, "net.x0pointer.foobar", "/a/path", "an.inter.face", "AMethod");
+ assert_se(r >= 0);
+
+ assert_se(pipe2(pipe_fds, O_CLOEXEC) >= 0);
+
+ assert_se(write(pipe_fds[1], "x", 1) == 1);
+
+ pipe_fds[1] = safe_close(pipe_fds[1]);
+
+ r = sd_bus_message_append(m, "h", pipe_fds[0]);
+ assert_se(r >= 0);
+
+ pipe_fds[0] = safe_close(pipe_fds[0]);
+
+ r = sd_bus_send(b, m, NULL);
+ assert_se(r >= 0);
+
+ for (;;) {
+ sd_bus_message_unref(m);
+ m = NULL;
+ r = sd_bus_process(a, &m);
+ assert_se(r > 0);
+ assert_se(m);
+
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
+ assert_se(sd_bus_message_rewind(m, true) >= 0);
+
+ if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) {
+ int fd;
+ char x;
+
+ r = sd_bus_message_read(m, "h", &fd);
+ assert_se(r >= 0);
+
+ assert_se(read(fd, &x, 1) == 1);
+ assert_se(x == 'x');
+ break;
+ }
+ }
+
+ r = sd_bus_release_name(a, "net.x0pointer.foobar");
+ assert_se(r >= 0);
+
+ r = sd_bus_release_name(a, "net.x0pointer.foobar");
+ assert_se(r == -ESRCH);
+
+ r = sd_bus_try_close(a);
+ assert_se(r >= 0);
+
+ sd_bus_unref(a);
+ sd_bus_unref(b);
+
+ return 0;
+}
--- /dev/null
+/***
+ 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 <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/mman.h>
+
+#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 "process-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 = 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;
+}
if (path_is_mount_point(u->runtime_path, NULL, 0) <= 0) {
_cleanup_free_ char *t = NULL;
- (void) mkdir_label(u->runtime_path, 0700);
+ r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu%s",
+ u->uid, u->gid, u->manager->runtime_dir_size,
+ mac_smack_use() ? ",smackfsroot=*" : "");
+ if (r < 0)
+ return log_oom();
- if (mac_smack_use())
- r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
- else
- r = asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size);
- if (r < 0) {
- r = log_oom();
- goto fail;
- }
+ (void) mkdir_label(u->runtime_path, 0700);
- r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t);
+ r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID|MS_NOEXEC, t);
if (r < 0) {
if (!IN_SET(errno, EPERM, EACCES)) {
r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
- ../TEST-01-BASIC/Makefile
-BUILD_DIR=$(shell ../../tools/find-build-dir.sh)
-
-all setup clean run:
- @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@
++../TEST-01-BASIC/Makefile
umount $TESTDIR/root
}
+test_cleanup() {
+ umount $TESTDIR/root 2>/dev/null
+ [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+ return 0
+}
+
do_test "$@"
-
- #!/bin/sh -eu
+ #!/bin/sh
+ set -eu
+relpath() {
+ python -c 'import os.path, sys;\
+ print os.path.relpath(sys.argv[1],sys.argv[2])' "$1" "${2-$PWD}"
+}
+
# this is needed mostly because $DESTDIR is provided as a variable,
# and we need to create the target directory...
Documentation=https://www.freedesktop.org/wiki/Software/systemd/resolved
Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
Documentation=https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
- After=systemd-networkd.service network.target
- Before=network-online.target nss-lookup.target
+ DefaultDependencies=no
+ After=systemd-sysusers.service systemd-networkd.service
+ Before=network.target nss-lookup.target shutdown.target
+ Conflicts=shutdown.target
Wants=nss-lookup.target
+# On kdbus systems we pull in the busname explicitly, because it
+# carries policy that allows the daemon to acquire its name.
+Wants=org.freedesktop.resolve1.busname
+After=org.freedesktop.resolve1.busname
+
[Service]
Type=notify
Restart=always
#!/bin/sh
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
systemctl --user import-environment DISPLAY XAUTHORITY
- if which dbus-update-activation-environment >/dev/null 2>&1; then
+ if command -v dbus-update-activation-environment >/dev/null 2>&1; then
dbus-update-activation-environment DISPLAY XAUTHORITY
fi