summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdrian Szyndela <adrian.s@samsung.com>2020-02-17 13:23:57 +0100
committerAdrian Szyndela <adrian.s@samsung.com>2020-02-26 12:21:20 +0100
commit8c75c63b9c27c5fd76c8029a315ff7dcf4d29ab4 (patch)
treedac037a5f82119253e1556eb8684ea8a91e5fed8 /src
parent71dda51708c0f9cafff337fda0a02322981dc48c (diff)
parentc1719d8bc924ed59448616bd748671c5c7a66d93 (diff)
downloadsystemd-8c75c63b9c27c5fd76c8029a315ff7dcf4d29ab4.tar.gz
systemd-8c75c63b9c27c5fd76c8029a315ff7dcf4d29ab4.tar.bz2
systemd-8c75c63b9c27c5fd76c8029a315ff7dcf4d29ab4.zip
Merge v235 into tizen
Change-Id: Iafcca23df73f2694eda50a97771acac4b7996f30
Diffstat (limited to 'src')
-rw-r--r--src/.gitignore8
-rw-r--r--src/Makefile28
l---------src/ac-power/Makefile1
l---------src/activate/Makefile1
-rw-r--r--src/activate/activate.c5
-rw-r--r--src/analyze/.gitignore1
l---------src/analyze/Makefile1
-rw-r--r--src/analyze/analyze-verify.c6
-rw-r--r--src/analyze/analyze-verify.h6
-rw-r--r--src/analyze/analyze.c87
l---------src/ask-password/Makefile1
l---------src/backlight/Makefile1
-rw-r--r--src/basic/.gitignore16
l---------src/basic/Makefile1
-rw-r--r--src/basic/alloc-util.c27
-rw-r--r--src/basic/alloc-util.h10
-rw-r--r--src/basic/audit-util.c4
-rw-r--r--src/basic/audit-util.h4
-rw-r--r--src/basic/barrier.c2
-rw-r--r--src/basic/barrier.h7
-rw-r--r--src/basic/blkid-util.h4
-rw-r--r--src/basic/bpf-program.c183
-rw-r--r--src/basic/bpf-program.h55
-rw-r--r--src/basic/btrfs-util.c2
-rw-r--r--src/basic/build.h40
-rw-r--r--src/basic/bus-label.h4
-rw-r--r--src/basic/calendarspec.c131
-rw-r--r--src/basic/calendarspec.h1
-rw-r--r--src/basic/cap-list.c67
-rw-r--r--src/basic/cap-list.h3
-rw-r--r--src/basic/capability-util.c104
-rw-r--r--src/basic/capability-util.h2
-rw-r--r--src/basic/cgroup-util.c74
-rw-r--r--src/basic/conf-files.c53
-rw-r--r--src/basic/conf-files.h10
-rw-r--r--src/basic/cpu-set-util.c46
-rw-r--r--src/basic/cpu-set-util.h1
-rw-r--r--src/basic/def.h10
-rw-r--r--src/basic/env-util.c12
-rw-r--r--src/basic/env-util.h1
-rw-r--r--src/basic/escape.c4
-rw-r--r--src/basic/exec-util.c2
-rw-r--r--src/basic/exit-status.c15
-rw-r--r--src/basic/exit-status.h6
-rw-r--r--src/basic/extract-word.c2
-rw-r--r--src/basic/fd-util.c3
-rw-r--r--src/basic/fileio.c191
-rw-r--r--src/basic/fileio.h18
-rw-r--r--src/basic/fs-util.c17
-rw-r--r--src/basic/hashmap.c26
-rw-r--r--src/basic/hashmap.h4
-rw-r--r--src/basic/hexdecoct.c3
-rw-r--r--src/basic/hostname-util.c13
-rw-r--r--src/basic/in-addr-util.c132
-rw-r--r--src/basic/in-addr-util.h17
-rw-r--r--src/basic/io-util.h13
-rw-r--r--src/basic/journal-importer.c9
-rw-r--r--src/basic/log.c225
-rw-r--r--src/basic/log.h20
-rw-r--r--src/basic/memfd-util.c2
-rw-r--r--src/basic/meson.build21
-rw-r--r--src/basic/missing.h103
-rw-r--r--src/basic/missing_syscall.h52
-rw-r--r--src/basic/mkdir.c9
-rw-r--r--src/basic/mount-util.c77
-rw-r--r--src/basic/mount-util.h3
-rw-r--r--src/basic/parse-util.c4
-rw-r--r--src/basic/path-util.c25
-rw-r--r--src/basic/path-util.h12
-rw-r--r--src/basic/process-util.c172
-rw-r--r--src/basic/process-util.h18
-rw-r--r--src/basic/random-util.c10
-rw-r--r--src/basic/replace-var.c2
-rw-r--r--src/basic/replace-var.h2
-rw-r--r--src/basic/rlimit-util.c3
-rw-r--r--src/basic/rm-rf.c6
-rw-r--r--src/basic/securebits-util.c84
-rw-r--r--src/basic/securebits-util.h28
-rw-r--r--src/basic/selinux-util.c34
-rw-r--r--src/basic/set.c61
-rw-r--r--src/basic/set.h2
-rw-r--r--src/basic/signal-util.c2
-rw-r--r--src/basic/smack-util.c2
-rw-r--r--src/basic/socket-label.c2
-rw-r--r--src/basic/socket-util.c22
-rw-r--r--src/basic/socket-util.h20
-rw-r--r--src/basic/special.h1
-rw-r--r--src/basic/string-util.c31
-rw-r--r--src/basic/string-util.h13
-rw-r--r--src/basic/terminal-util.c75
-rw-r--r--src/basic/terminal-util.h25
-rw-r--r--src/basic/time-util.c202
-rw-r--r--src/basic/unit-name.c21
-rw-r--r--src/basic/unit-name.h21
-rw-r--r--src/basic/user-util.c3
-rw-r--r--src/basic/utf8.c2
-rw-r--r--src/basic/util.c135
-rw-r--r--src/basic/util.h3
-rw-r--r--src/basic/virt.c3
-rw-r--r--src/basic/xattr-util.c2
-rw-r--r--src/basic/xml.c2
l---------src/binfmt/Makefile1
-rw-r--r--src/binfmt/binfmt.c2
l---------src/boot/Makefile1
-rw-r--r--src/boot/bootctl.c14
-rw-r--r--src/boot/efi/.gitignore2
-rw-r--r--src/boot/efi/boot.c5
-rw-r--r--src/boot/efi/measure.c2
-rw-r--r--src/boot/efi/meson.build4
-rw-r--r--src/boot/efi/stub.c5
l---------src/cgls/Makefile1
l---------src/cgroups-agent/Makefile1
l---------src/cgtop/Makefile1
-rw-r--r--src/core/.gitignore3
l---------src/core/Makefile1
-rw-r--r--src/core/audit-fd.c4
-rw-r--r--src/core/automount.c14
-rw-r--r--src/core/bpf-firewall.c680
-rw-r--r--src/core/bpf-firewall.h32
-rw-r--r--src/core/busname.h69
-rw-r--r--src/core/cgroup.c477
-rw-r--r--src/core/cgroup.h36
-rw-r--r--src/core/chown-recursive.c152
-rw-r--r--src/core/chown-recursive.h (renamed from src/core/dbus-busname.h)5
-rw-r--r--src/core/dbus-busname.c37
-rw-r--r--src/core/dbus-cgroup.c195
-rw-r--r--src/core/dbus-execute.c633
-rw-r--r--src/core/dbus-service.c7
-rw-r--r--src/core/dbus-unit.c44
-rw-r--r--src/core/dbus.c8
-rw-r--r--src/core/device.c4
-rw-r--r--src/core/dynamic-user.c115
-rw-r--r--src/core/dynamic-user.h4
-rw-r--r--src/core/execute.c1241
-rw-r--r--src/core/execute.h75
-rw-r--r--src/core/ima-setup.c4
-rw-r--r--src/core/ip-address-access.c217
-rw-r--r--src/core/ip-address-access.h38
-rw-r--r--src/core/job.c27
-rw-r--r--src/core/killall.c3
-rw-r--r--src/core/kmod-setup.c51
-rw-r--r--src/core/load-fragment-gperf-nulstr.awk2
-rw-r--r--src/core/load-fragment-gperf.gperf.m441
-rw-r--r--src/core/load-fragment.c491
-rw-r--r--src/core/load-fragment.h10
-rw-r--r--src/core/macros.systemd.in1
-rw-r--r--src/core/main.c200
-rw-r--r--src/core/manager.c291
-rw-r--r--src/core/manager.h35
-rw-r--r--src/core/meson.build186
-rw-r--r--src/core/mount-setup.c24
-rw-r--r--src/core/mount.c326
-rw-r--r--src/core/mount.h2
-rw-r--r--src/core/namespace.c168
-rw-r--r--src/core/namespace.h1
-rw-r--r--src/core/path.c21
-rw-r--r--src/core/scope.c15
-rw-r--r--src/core/selinux-access.c6
-rw-r--r--src/core/selinux-access.h2
-rw-r--r--src/core/selinux-setup.c6
-rw-r--r--src/core/service.c259
-rw-r--r--src/core/service.h5
-rw-r--r--src/core/show-status.c14
-rw-r--r--src/core/shutdown.c2
-rw-r--r--src/core/slice.c3
-rw-r--r--src/core/smack-setup.c6
-rw-r--r--src/core/socket.c332
-rw-r--r--src/core/socket.h2
-rw-r--r--src/core/swap.c147
-rw-r--r--src/core/swap.h2
-rw-r--r--src/core/system.conf3
-rw-r--r--src/core/timer.c30
-rw-r--r--src/core/transaction.c133
-rw-r--r--src/core/transaction.h1
-rw-r--r--src/core/umount.c42
-rw-r--r--src/core/unit-printf.c6
-rw-r--r--src/core/unit.c418
-rw-r--r--src/core/unit.h50
l---------src/coredump/Makefile1
-rw-r--r--src/coredump/coredump.c40
-rw-r--r--src/coredump/coredumpctl.c2
-rw-r--r--src/coredump/meson.build2
-rw-r--r--src/coredump/stacktrace.c2
l---------src/cryptsetup/Makefile1
-rw-r--r--src/cryptsetup/cryptsetup-generator.c93
-rw-r--r--src/cryptsetup/cryptsetup.c12
l---------src/dbus1-generator/Makefile1
l---------src/debug-generator/Makefile1
l---------src/delta/Makefile1
-rw-r--r--src/delta/delta.c4
l---------src/detect-virt/Makefile1
l---------src/dissect/Makefile1
l---------src/environment-d-generator/Makefile1
-rw-r--r--src/environment-d-generator/environment-d-generator.c2
l---------src/escape/Makefile1
-rw-r--r--src/escape/escape.c2
l---------src/firstboot/Makefile1
-rw-r--r--src/firstboot/firstboot.c8
l---------src/fsck/Makefile1
-rw-r--r--src/fsck/fsck.c8
l---------src/fstab-generator/Makefile1
-rw-r--r--src/fstab-generator/fstab-generator.c51
l---------src/getty-generator/Makefile1
-rw-r--r--src/getty-generator/getty-generator.c8
l---------src/gpt-auto-generator/Makefile1
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c213
l---------src/hibernate-resume/Makefile1
-rw-r--r--src/hostname/.gitignore1
l---------src/hostname/Makefile1
-rw-r--r--src/hostname/meson.build2
l---------src/hwdb/Makefile1
-rw-r--r--src/hwdb/hwdb.c27
-rw-r--r--src/import/.gitignore1
l---------src/import/Makefile1
-rw-r--r--src/import/import-common.c2
-rw-r--r--src/import/import-compress.c12
-rw-r--r--src/import/importd.c9
-rw-r--r--src/import/meson.build2
-rw-r--r--src/import/pull-job.c7
-rw-r--r--src/import/qcow2-util.c3
l---------src/initctl/Makefile1
-rw-r--r--src/initctl/initctl.c4
-rw-r--r--src/journal-remote/.gitignore2
l---------src/journal-remote/Makefile1
-rw-r--r--src/journal-remote/journal-gatewayd.c8
-rw-r--r--src/journal-remote/journal-remote.c49
-rw-r--r--src/journal-remote/journal-upload.c2
-rw-r--r--src/journal-remote/meson.build4
-rw-r--r--src/journal-remote/microhttpd-util.c4
-rw-r--r--src/journal-remote/microhttpd-util.h25
-rw-r--r--src/journal/.gitignore3
l---------src/journal/Makefile1
-rw-r--r--src/journal/audit-type.c2
-rw-r--r--src/journal/catalog.c6
-rw-r--r--src/journal/compress.c32
-rw-r--r--src/journal/compress.h4
-rw-r--r--src/journal/journal-def.h8
-rw-r--r--src/journal/journal-file.c231
-rw-r--r--src/journal/journal-file.h6
-rw-r--r--src/journal/journal-qrcode.c4
-rw-r--r--src/journal/journal-send.c72
-rw-r--r--src/journal/journal-verify.c50
-rw-r--r--src/journal/journalctl.c26
-rw-r--r--src/journal/journald-audit.c26
-rw-r--r--src/journal/journald-console.c22
-rw-r--r--src/journal/journald-context.c588
-rw-r--r--src/journal/journald-context.h92
-rw-r--r--src/journal/journald-gperf.gperf2
-rw-r--r--src/journal/journald-kmsg.c73
-rw-r--r--src/journal/journald-native.c21
-rw-r--r--src/journal/journald-rate-limit.c7
-rw-r--r--src/journal/journald-server.c547
-rw-r--r--src/journal/journald-server.h15
-rw-r--r--src/journal/journald-stream.c168
-rw-r--r--src/journal/journald-syslog.c53
-rw-r--r--src/journal/journald.c6
-rw-r--r--src/journal/journald.conf1
-rw-r--r--src/journal/meson.build32
-rw-r--r--src/journal/mmap-cache.c54
-rw-r--r--src/journal/mmap-cache.h3
-rw-r--r--src/journal/sd-journal.c14
-rw-r--r--src/journal/test-compress-benchmark.c22
-rw-r--r--src/journal/test-compress.c18
-rw-r--r--src/journal/test-journal.c2
-rw-r--r--src/journal/test-mmap-cache.c10
l---------src/kernel-install/Makefile1
l---------src/libsystemd-network/Makefile1
-rw-r--r--src/libsystemd-network/dhcp-network.c16
-rw-r--r--src/libsystemd-network/dhcp-packet.c4
-rw-r--r--src/libsystemd-network/icmp6-util.c2
-rw-r--r--src/libsystemd-network/radv-internal.h14
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c97
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c16
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c4
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c2
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c2
-rw-r--r--src/libsystemd-network/sd-lldp.c2
-rw-r--r--src/libsystemd-network/sd-radv.c109
-rw-r--r--src/libsystemd-network/test-dhcp-client.c61
-rw-r--r--src/libsystemd-network/test-ndisc-ra.c31
-rw-r--r--src/libsystemd/.gitignore1
l---------src/libsystemd/Makefile1
l---------src/libsystemd/sd-bus/Makefile1
-rw-r--r--src/libsystemd/sd-bus/bus-container.c135
-rw-r--r--src/libsystemd/sd-bus/bus-container.h1
-rw-r--r--src/libsystemd/sd-bus/bus-control.c1003
-rw-r--r--src/libsystemd/sd-bus/bus-control.h9
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c16
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c26
-rw-r--r--src/libsystemd/sd-bus/bus-internal.c2
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h84
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.c42
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c1675
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.h53
-rw-r--r--src/libsystemd/sd-bus/bus-match.c22
-rw-r--r--src/libsystemd/sd-bus/bus-message.c110
-rw-r--r--src/libsystemd/sd-bus/bus-message.h4
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c22
-rw-r--r--src/libsystemd/sd-bus/bus-slot.c2
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c17
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c384
-rw-r--r--src/libsystemd/sd-bus/test-bus-benchmark.c38
-rw-r--r--src/libsystemd/sd-bus/test-bus-cleanup.c8
-rw-r--r--src/libsystemd/sd-bus/test-bus-gvariant.c8
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel-bloom.c141
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel.c190
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c10
-rw-r--r--src/libsystemd/sd-bus/test-bus-match.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-track.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-zero-copy.c210
l---------src/libsystemd/sd-daemon/Makefile1
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c15
l---------src/libsystemd/sd-device/Makefile1
-rw-r--r--src/libsystemd/sd-device/device-internal.h2
-rw-r--r--src/libsystemd/sd-device/device-private.c2
-rw-r--r--src/libsystemd/sd-device/sd-device.c4
l---------src/libsystemd/sd-event/Makefile1
-rw-r--r--src/libsystemd/sd-event/sd-event.c21
-rw-r--r--src/libsystemd/sd-event/test-event.c10
l---------src/libsystemd/sd-hwdb/Makefile1
-rw-r--r--src/libsystemd/sd-hwdb/sd-hwdb.c2
l---------src/libsystemd/sd-id128/Makefile1
-rw-r--r--src/libsystemd/sd-id128/id128-util.c2
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c2
l---------src/libsystemd/sd-login/Makefile1
-rw-r--r--src/libsystemd/sd-login/test-login.c17
l---------src/libsystemd/sd-netlink/Makefile1
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.c2
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c8
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c32
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h4
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c208
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c14
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c2
l---------src/libsystemd/sd-network/Makefile1
-rw-r--r--src/libsystemd/sd-network/sd-network.c2
l---------src/libsystemd/sd-path/Makefile1
-rw-r--r--src/libsystemd/sd-path/sd-path.c11
l---------src/libsystemd/sd-resolve/Makefile1
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c4
l---------src/libsystemd/sd-utf8/Makefile1
-rw-r--r--src/libudev/.gitignore1
l---------src/libudev/Makefile1
-rw-r--r--src/libudev/libudev-enumerate.c8
-rw-r--r--src/libudev/libudev-hwdb.c17
-rw-r--r--src/libudev/libudev-monitor.c39
-rw-r--r--src/libudev/libudev-queue.c13
-rw-r--r--src/libudev/libudev.c3
-rw-r--r--src/libudev/meson.build2
-rw-r--r--src/locale/.gitignore1
l---------src/locale/Makefile1
-rw-r--r--src/locale/keymap-util.c24
-rw-r--r--src/locale/localed.c4
-rw-r--r--src/locale/meson.build4
-rw-r--r--src/login/.gitignore6
l---------src/login/Makefile1
-rw-r--r--src/login/loginctl.c2
-rw-r--r--src/login/logind-acl.h2
-rw-r--r--src/login/logind-core.c44
-rw-r--r--src/login/logind-dbus.c297
-rw-r--r--src/login/logind-gperf.gperf2
-rw-r--r--src/login/logind-seat.c7
-rw-r--r--src/login/logind-session-dbus.c2
-rw-r--r--src/login/logind-session.c20
-rw-r--r--src/login/logind-user.c42
-rw-r--r--src/login/logind-utmp.c11
-rw-r--r--src/login/logind.c4
-rw-r--r--src/login/logind.h1
-rw-r--r--src/login/meson.build4
-rw-r--r--src/login/org.freedesktop.login1.conf8
-rw-r--r--src/login/org.freedesktop.login1.policy.in33
-rw-r--r--src/login/pam_systemd.c10
l---------src/machine-id-setup/Makefile1
-rw-r--r--src/machine/.gitignore1
l---------src/machine/Makefile1
-rw-r--r--src/machine/machine.c6
-rw-r--r--src/machine/machinectl.c6
-rw-r--r--src/machine/machined.c5
-rw-r--r--src/machine/meson.build2
l---------src/modules-load/Makefile1
-rw-r--r--src/modules-load/modules-load.c2
l---------src/mount/Makefile1
-rw-r--r--src/mount/mount-tool.c22
-rw-r--r--src/network/.gitignore2
l---------src/network/Makefile1
-rw-r--r--src/network/meson.build4
-rw-r--r--src/network/netdev/.gitignore1
l---------src/network/netdev/Makefile1
-rw-r--r--src/network/netdev/bridge.c6
-rw-r--r--src/network/netdev/bridge.h1
-rw-r--r--src/network/netdev/netdev-gperf.gperf5
-rw-r--r--src/network/netdev/netdev.c43
-rw-r--r--src/network/netdev/tunnel.c67
-rw-r--r--src/network/netdev/tunnel.h1
-rw-r--r--src/network/netdev/vrf.c2
-rw-r--r--src/network/netdev/vrf.h2
-rw-r--r--src/network/networkctl.c2
-rw-r--r--src/network/networkd-address.c51
-rw-r--r--src/network/networkd-address.h1
-rw-r--r--src/network/networkd-conf.c2
-rw-r--r--src/network/networkd-dhcp4.c54
-rw-r--r--src/network/networkd-link.c119
-rw-r--r--src/network/networkd-manager.c224
-rw-r--r--src/network/networkd-manager.h6
-rw-r--r--src/network/networkd-network-gperf.gperf15
-rw-r--r--src/network/networkd-network.c210
-rw-r--r--src/network/networkd-network.h20
-rw-r--r--src/network/networkd-radv.c19
-rw-r--r--src/network/networkd-route.c65
-rw-r--r--src/network/networkd-route.h4
-rw-r--r--src/network/networkd-routing-policy-rule.c900
-rw-r--r--src/network/networkd-routing-policy-rule.h83
-rw-r--r--src/network/networkd-util.c3
-rw-r--r--src/network/networkd.c24
l---------src/network/wait-online/Makefile1
l---------src/notify/Makefile1
-rw-r--r--src/nspawn/.gitignore1
l---------src/nspawn/Makefile1
-rw-r--r--src/nspawn/nspawn-gperf.gperf1
-rw-r--r--src/nspawn/nspawn-mount.c7
-rw-r--r--src/nspawn/nspawn-patch-uid.c6
-rw-r--r--src/nspawn/nspawn-seccomp.c253
-rw-r--r--src/nspawn/nspawn-seccomp.h2
-rw-r--r--src/nspawn/nspawn-settings.c50
-rw-r--r--src/nspawn/nspawn-settings.h6
-rw-r--r--src/nspawn/nspawn.c105
l---------src/nss-myhostname/Makefile1
-rw-r--r--src/nss-myhostname/nss-myhostname.c10
l---------src/nss-mymachines/Makefile1
-rw-r--r--src/nss-mymachines/nss-mymachines.c8
l---------src/nss-resolve/Makefile1
-rw-r--r--src/nss-resolve/nss-resolve.c2
l---------src/nss-systemd/Makefile1
-rw-r--r--src/nss-systemd/nss-systemd.c213
l---------src/path/Makefile1
l---------src/quotacheck/Makefile1
-rw-r--r--src/quotacheck/quotacheck.c4
l---------src/random-seed/Makefile1
l---------src/rc-local-generator/Makefile1
l---------src/remount-fs/Makefile1
l---------src/reply-password/Makefile1
-rw-r--r--src/resolve/.gitignore6
l---------src/resolve/Makefile1
-rw-r--r--src/resolve/meson.build12
-rw-r--r--src/resolve/resolve-tool.c79
-rw-r--r--src/resolve/resolved-bus.c15
-rw-r--r--src/resolve/resolved-conf.c2
-rw-r--r--src/resolve/resolved-dns-dnssec.c8
-rw-r--r--src/resolve/resolved-dns-packet.c27
-rw-r--r--src/resolve/resolved-dns-packet.h22
-rw-r--r--src/resolve/resolved-dns-query.c11
-rw-r--r--src/resolve/resolved-dns-scope.c6
-rw-r--r--src/resolve/resolved-dns-server.c86
-rw-r--r--src/resolve/resolved-dns-server.h5
-rw-r--r--src/resolve/resolved-dns-stream.c8
-rw-r--r--src/resolve/resolved-dns-stub.c58
-rw-r--r--src/resolve/resolved-dns-synthesize.c97
-rw-r--r--src/resolve/resolved-dns-transaction.c7
-rw-r--r--src/resolve/resolved-dns-trust-anchor.c2
-rw-r--r--src/resolve/resolved-link.c53
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-llmnr.c2
-rw-r--r--src/resolve/resolved-manager.c51
-rw-r--r--src/resolve/resolved-manager.h2
-rw-r--r--src/resolve/resolved-mdns.c18
-rw-r--r--src/resolve/resolved-resolv-conf.c40
-rw-r--r--src/resolve/resolved.c21
-rw-r--r--src/resolve/test-dns-packet.c4
-rw-r--r--src/resolve/test-dnssec-complex.c2
-rw-r--r--src/resolve/test-dnssec.c4
-rw-r--r--src/resolve/test-resolved-packet.c7
l---------src/rfkill/Makefile1
-rw-r--r--src/rfkill/rfkill.c131
l---------src/run/Makefile1
-rw-r--r--src/run/run.c105
l---------src/shared/Makefile1
-rw-r--r--src/shared/acl-util.h2
-rw-r--r--src/shared/ask-password-api.c10
-rw-r--r--src/shared/bus-unit-util.c432
-rw-r--r--src/shared/bus-util.c114
-rw-r--r--src/shared/clean-ipc.c162
-rw-r--r--src/shared/clean-ipc.h11
-rw-r--r--src/shared/condition.c7
-rw-r--r--src/shared/conf-parser.c101
-rw-r--r--src/shared/dissect-image.c39
-rw-r--r--src/shared/dns-domain.c48
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/dropin.c9
-rw-r--r--src/shared/efivars.c4
-rw-r--r--src/shared/efivars.h2
-rw-r--r--src/shared/firewall-util.c8
-rw-r--r--src/shared/firewall-util.h2
-rw-r--r--src/shared/gcrypt-util.c2
-rw-r--r--src/shared/gcrypt-util.h6
-rw-r--r--src/shared/generator.c34
-rw-r--r--src/shared/generator.h2
-rw-r--r--src/shared/install.c127
-rw-r--r--src/shared/install.h14
-rw-r--r--src/shared/journal-util.c4
-rw-r--r--src/shared/libshared.sym3
-rw-r--r--src/shared/linux/bpf.h673
-rw-r--r--src/shared/linux/bpf_common.h55
-rw-r--r--src/shared/linux/libbpf.h198
-rw-r--r--src/shared/logs-show.c9
-rw-r--r--src/shared/machine-image.c6
-rw-r--r--src/shared/meson.build13
-rw-r--r--src/shared/pager.c4
-rw-r--r--src/shared/path-lookup.c142
-rw-r--r--src/shared/path-lookup.h6
-rw-r--r--src/shared/ptyfwd.c10
-rw-r--r--src/shared/seccomp-util.c428
-rw-r--r--src/shared/seccomp-util.h14
-rw-r--r--src/shared/spawn-polkit-agent.c2
-rw-r--r--src/shared/specifier.c4
-rw-r--r--src/shared/utmp-wtmp.c2
-rw-r--r--src/shared/utmp-wtmp.h6
l---------src/sleep/Makefile1
-rw-r--r--src/sleep/sleep.c7
l---------src/socket-proxy/Makefile1
-rw-r--r--src/socket-proxy/socket-proxyd.c8
-rw-r--r--src/sulogin-shell/.gitignore1
-rw-r--r--src/sulogin-shell/meson.build15
-rw-r--r--src/sulogin-shell/sulogin-shell.c105
-rwxr-xr-xsrc/sulogin-shell/systemd-sulogin-shell.in12
l---------src/sysctl/Makefile1
-rw-r--r--src/sysctl/sysctl.c4
l---------src/system-update-generator/Makefile1
l---------src/systemctl/Makefile1
-rw-r--r--src/systemctl/systemctl.c236
l---------src/systemd/Makefile1
-rw-r--r--src/systemd/sd-dhcp-client.h16
-rw-r--r--src/systemd/sd-messages.h7
-rw-r--r--src/systemd/sd-netlink.h14
-rw-r--r--src/systemd/sd-radv.h3
l---------src/sysusers/Makefile1
-rw-r--r--src/sysusers/sysusers.c32
l---------src/sysv-generator/Makefile1
-rw-r--r--src/sysv-generator/sysv-generator.c35
-rw-r--r--src/test/.gitignore1
l---------src/test/Makefile1
-rw-r--r--src/test/meson.build51
-rw-r--r--src/test/test-architecture.c2
-rw-r--r--src/test/test-bpf.c162
-rw-r--r--src/test/test-calendarspec.c12
-rw-r--r--src/test/test-cap-list.c15
-rw-r--r--src/test/test-capability.c2
-rw-r--r--src/test/test-cgroup-mask.c6
-rw-r--r--src/test/test-cgroup-util.c3
-rw-r--r--src/test/test-cgroup.c6
-rw-r--r--src/test/test-clock.c4
-rw-r--r--src/test/test-condition.c10
-rw-r--r--src/test/test-conf-files.c4
-rw-r--r--src/test/test-conf-parser.c136
-rw-r--r--src/test/test-copy.c16
-rw-r--r--src/test/test-cpu-set-util.c2
-rw-r--r--src/test/test-daemon.c19
-rw-r--r--src/test/test-date.c17
-rw-r--r--src/test/test-dns-domain.c15
-rw-r--r--src/test/test-engine.c4
-rw-r--r--src/test/test-exec-util.c25
-rw-r--r--src/test/test-execute.c26
-rw-r--r--src/test/test-fileio.c110
-rw-r--r--src/test/test-hashmap-plain.c73
-rw-r--r--src/test/test-helper.c41
-rw-r--r--src/test/test-helper.h2
-rw-r--r--src/test/test-in-addr-util.c75
-rw-r--r--src/test/test-install-root.c14
-rw-r--r--src/test/test-log.c6
-rw-r--r--src/test/test-ns.c1
-rw-r--r--src/test/test-nss.c10
-rw-r--r--src/test/test-path-util.c18
-rw-r--r--src/test/test-path.c4
-rw-r--r--src/test/test-process-util.c216
-rw-r--r--src/test/test-sched-prio.c4
-rw-r--r--src/test/test-seccomp.c93
-rw-r--r--src/test/test-set.c45
-rw-r--r--src/test/test-sigbus.c4
-rw-r--r--src/test/test-signal-util.c10
-rw-r--r--src/test/test-sizeof.c2
-rw-r--r--src/test/test-string-util.c7
-rw-r--r--src/test/test-tables.c4
-rw-r--r--src/test/test-tmpfiles.c4
-rw-r--r--src/test/test-unit-file.c19
-rw-r--r--src/test/test-unit-name.c22
-rw-r--r--src/test/test-watchdog.c16
-rw-r--r--src/timedate/.gitignore1
l---------src/timedate/Makefile1
-rw-r--r--src/timedate/meson.build2
-rw-r--r--src/timedate/timedatectl.c20
-rw-r--r--src/timesync/.gitignore2
l---------src/timesync/Makefile1
-rw-r--r--src/timesync/meson.build2
-rw-r--r--src/timesync/timesyncd-manager.c6
-rw-r--r--src/timesync/timesyncd.c40
l---------src/tmpfiles/Makefile1
-rw-r--r--src/tmpfiles/tmpfiles.c54
l---------src/tty-ask-password-agent/Makefile1
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c7
-rw-r--r--src/udev/.gitignore4
l---------src/udev/Makefile1
l---------src/udev/ata_id/Makefile1
-rw-r--r--src/udev/ata_id/ata_id.c5
l---------src/udev/cdrom_id/Makefile1
-rw-r--r--src/udev/cdrom_id/cdrom_id.c2
l---------src/udev/collect/Makefile1
-rw-r--r--src/udev/collect/collect.c2
-rw-r--r--src/udev/meson.build6
l---------src/udev/mtd_probe/Makefile1
-rw-r--r--src/udev/mtd_probe/probe_smartmedia.c2
-rw-r--r--src/udev/net/.gitignore1
l---------src/udev/net/Makefile1
-rw-r--r--src/udev/net/ethtool-util.c92
-rw-r--r--src/udev/net/ethtool-util.h6
-rw-r--r--src/udev/net/link-config-gperf.gperf1
-rw-r--r--src/udev/net/link-config.c4
-rw-r--r--src/udev/scsi_id/.gitignore1
l---------src/udev/scsi_id/Makefile1
-rw-r--r--src/udev/scsi_id/scsi_id.c2
-rw-r--r--src/udev/scsi_id/scsi_serial.c15
-rw-r--r--src/udev/udev-builtin-blkid.c2
-rw-r--r--src/udev/udev-builtin-btrfs.c2
-rw-r--r--src/udev/udev-builtin-path_id.c2
-rw-r--r--src/udev/udev-builtin-uaccess.c2
-rw-r--r--src/udev/udev-builtin-usb_id.c2
-rw-r--r--src/udev/udev-builtin.c6
-rw-r--r--src/udev/udev-event.c15
-rw-r--r--src/udev/udev-node.c6
-rw-r--r--src/udev/udev-rules.c95
-rw-r--r--src/udev/udev.h10
-rw-r--r--src/udev/udevadm-hwdb.c44
-rw-r--r--src/udev/udevadm-monitor.c2
-rw-r--r--src/udev/udevadm-test-builtin.c3
-rw-r--r--src/udev/udevadm-trigger.c2
-rw-r--r--src/udev/udevadm-util.c5
-rw-r--r--src/udev/udevd.c8
l---------src/udev/v4l_id/Makefile1
l---------src/update-done/Makefile1
l---------src/update-utmp/Makefile1
-rw-r--r--src/update-utmp/update-utmp.c27
l---------src/user-sessions/Makefile1
-rw-r--r--src/vconsole/.gitignore1
l---------src/vconsole/Makefile1
-rw-r--r--src/vconsole/meson.build2
l---------src/veritysetup/Makefile1
-rw-r--r--src/veritysetup/veritysetup.c2
l---------src/volatile-root/Makefile1
646 files changed, 17980 insertions, 9655 deletions
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644
index e6ac2d7b8a..0000000000
--- a/src/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-load-fragment-gperf-nulstr.c
-load-fragment-gperf.c
-load-fragment-gperf.gperf
-org.freedesktop.systemd1.policy.in
-org.freedesktop.systemd1.policy
-99-systemd.rules
-*.gcno
-*.gcda
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index 9d07505194..0000000000
--- a/src/Makefile
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file is part of systemd.
-#
-# Copyright 2010 Lennart Poettering
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
-
-# This file is a dirty trick to simplify compilation from within
-# emacs. This file is not intended to be distributed. So, don't touch
-# it, even better ignore it!
-
-all:
- $(MAKE) -C ..
-
-clean:
- $(MAKE) -C .. clean
-
-.PHONY: all clean
diff --git a/src/ac-power/Makefile b/src/ac-power/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/ac-power/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/activate/Makefile b/src/activate/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/activate/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 6ebd820410..4b82dca491 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -31,6 +31,7 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "process-util.h"
#include "signal-util.h"
#include "socket-util.h"
#include "string-util.h"
@@ -221,7 +222,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%i", n_fds) < 0)
return log_oom();
- if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0)
+ if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid_cached()) < 0)
return log_oom();
if (arg_fdnames) {
@@ -271,7 +272,7 @@ static int fork_and_exec_process(const char* child, char** argv, char **env, int
if (!joined)
return log_oom();
- parent_pid = getpid();
+ parent_pid = getpid_cached();
child_pid = fork();
if (child_pid < 0)
diff --git a/src/analyze/.gitignore b/src/analyze/.gitignore
deleted file mode 100644
index 752ea236c8..0000000000
--- a/src/analyze/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/systemd-analyze
diff --git a/src/analyze/Makefile b/src/analyze/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/analyze/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
index 0ce0276d92..f34c24c53a 100644
--- a/src/analyze/analyze-verify.c
+++ b/src/analyze/analyze-verify.c
@@ -242,7 +242,7 @@ static int verify_unit(Unit *u, bool check_man) {
return r;
}
-int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators) {
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
_cleanup_free_ char *var = NULL;
Manager *m = NULL;
@@ -253,6 +253,8 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
Unit *units[strv_length(filenames)];
int i, count = 0;
+ const uint8_t flags = MANAGER_TEST_RUN_ENV_GENERATORS |
+ run_generators * MANAGER_TEST_RUN_GENERATORS;
if (strv_isempty(filenames))
return 0;
@@ -264,7 +266,7 @@ int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
assert_se(set_unit_path(var) >= 0);
- r = manager_new(scope, true, &m);
+ r = manager_new(scope, flags, &m);
if (r < 0)
return log_error_errno(r, "Failed to initialize manager: %m");
diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h
index d8204dc69c..d5466ecdf9 100644
--- a/src/analyze/analyze-verify.h
+++ b/src/analyze/analyze-verify.h
@@ -23,4 +23,8 @@
#include "path-lookup.h"
-int verify_units(char **filenames, UnitFileScope scope, bool check_man);
+int verify_units(
+ char **filenames,
+ UnitFileScope scope,
+ bool check_man,
+ bool run_generators);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 1eb2ca0ccf..9fcc20dba3 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -36,7 +36,7 @@
#include "log.h"
#include "pager.h"
#include "parse-util.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "special.h"
@@ -79,6 +79,7 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static char *arg_host = NULL;
static bool arg_user = false;
static bool arg_man = true;
+static bool arg_generators = false;
struct boot_times {
usec_t firmware_time;
@@ -1253,6 +1254,34 @@ static int set_log_level(sd_bus *bus, char **args) {
return 0;
}
+static int get_log_level(sd_bus *bus, char **args) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+ _cleanup_free_ char *level = NULL;
+
+ assert(bus);
+ assert(args);
+
+ if (!strv_isempty(args)) {
+ log_error("Too many arguments.");
+ return -E2BIG;
+ }
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LogLevel",
+ &error,
+ &level);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get log level: %s", bus_error_message(&error, r));
+
+ puts(level);
+ return 0;
+}
+
static int set_log_target(sd_bus *bus, char **args) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -1280,7 +1309,35 @@ static int set_log_target(sd_bus *bus, char **args) {
return 0;
}
-#ifdef HAVE_SECCOMP
+static int get_log_target(sd_bus *bus, char **args) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+ _cleanup_free_ char *target = NULL;
+
+ assert(bus);
+ assert(args);
+
+ if (!strv_isempty(args)) {
+ log_error("Too many arguments.");
+ return -E2BIG;
+ }
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LogTarget",
+ &error,
+ &target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get log target: %s", bus_error_message(&error, r));
+
+ puts(target);
+ return 0;
+}
+
+#if HAVE_SECCOMP
static void dump_syscall_filter(const SyscallFilterSet *set) {
const char *syscall;
@@ -1357,6 +1414,7 @@ static void help(void) {
" --fuzz=SECONDS Also print also services which finished SECONDS\n"
" earlier than the latest in the branch\n"
" --man[=BOOL] Do [not] check for existence of man pages\n\n"
+ " --generators[=BOOL] Do [not] run unit generators (requires privileges)\n\n"
"Commands:\n"
" time Print time spent in the kernel\n"
" blame Print list of running units ordered by time to init\n"
@@ -1365,6 +1423,8 @@ static void help(void) {
" dot Output dependency graph in man:dot(1) format\n"
" set-log-level LEVEL Set logging threshold for manager\n"
" set-log-target TARGET Set logging target for manager\n"
+ " get-log-level Get logging threshold for manager\n"
+ " get-log-target Get logging target for manager\n"
" dump Output state serialization of service manager\n"
" syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
" verify FILE... Check unit files for correctness\n"
@@ -1387,6 +1447,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FUZZ,
ARG_NO_PAGER,
ARG_MAN,
+ ARG_GENERATORS,
};
static const struct option options[] = {
@@ -1401,6 +1462,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "fuzz", required_argument, NULL, ARG_FUZZ },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "man", optional_argument, NULL, ARG_MAN },
+ { "generators", optional_argument, NULL, ARG_GENERATORS },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{}
@@ -1483,6 +1545,20 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_GENERATORS:
+ if (optarg) {
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --generators= argument.");
+ return -EINVAL;
+ }
+
+ arg_generators = !!r;
+ } else
+ arg_generators = true;
+
+ break;
+
case '?':
return -EINVAL;
@@ -1508,7 +1584,8 @@ int main(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "verify"))
r = verify_units(argv+optind+1,
arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
- arg_man);
+ arg_man,
+ arg_generators);
else {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -1532,8 +1609,12 @@ int main(int argc, char *argv[]) {
r = dump(bus, argv+optind+1);
else if (streq(argv[optind], "set-log-level"))
r = set_log_level(bus, argv+optind+1);
+ else if (streq(argv[optind], "get-log-level"))
+ r = get_log_level(bus, argv+optind+1);
else if (streq(argv[optind], "set-log-target"))
r = set_log_target(bus, argv+optind+1);
+ else if (streq(argv[optind], "get-log-target"))
+ r = get_log_target(bus, argv+optind+1);
else if (streq(argv[optind], "syscall-filter"))
r = dump_syscall_filters(argv+optind+1);
else
diff --git a/src/ask-password/Makefile b/src/ask-password/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/ask-password/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/backlight/Makefile b/src/backlight/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/backlight/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/basic/.gitignore b/src/basic/.gitignore
deleted file mode 100644
index e22411e484..0000000000
--- a/src/basic/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-/cap-from-name.gperf
-/cap-from-name.h
-/cap-list.txt
-/cap-to-name.h
-/errno-from-name.gperf
-/errno-from-name.h
-/errno-list.txt
-/errno-to-name.h
-/af-from-name.gperf
-/af-from-name.h
-/af-list.txt
-/af-to-name.h
-/arphrd-from-name.gperf
-/arphrd-from-name.h
-/arphrd-list.txt
-/arphrd-to-name.h
diff --git a/src/basic/Makefile b/src/basic/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/basic/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c
index b540dcddf5..948389f276 100644
--- a/src/basic/alloc-util.c
+++ b/src/basic/alloc-util.c
@@ -25,16 +25,31 @@
#include "util.h"
void* memdup(const void *p, size_t l) {
- void *r;
+ void *ret;
- assert(p);
+ assert(l == 0 || p);
+
+ ret = malloc(l);
+ if (!ret)
+ return NULL;
+
+ memcpy(ret, p, l);
+ return ret;
+}
+
+void* memdup_suffix0(const void*p, size_t l) {
+ void *ret;
+
+ assert(l == 0 || p);
+
+ /* The same as memdup() but place a safety NUL byte after the allocated memory */
- r = malloc(l);
- if (!r)
+ ret = malloc(l + 1);
+ if (!ret)
return NULL;
- memcpy(r, p, l);
- return r;
+ *((uint8_t*) mempcpy(ret, p, l)) = 0;
+ return ret;
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
index a44dd473c1..0a89691bae 100644
--- a/src/basic/alloc-util.h
+++ b/src/basic/alloc-util.h
@@ -36,6 +36,8 @@
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
+#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
+
#define malloc0(n) (calloc(1, (n)))
static inline void *mfree(void *memory) {
@@ -52,6 +54,7 @@ static inline void *mfree(void *memory) {
})
void* memdup(const void *p, size_t l) _alloc_(2);
+void* memdup_suffix0(const void*p, size_t l) _alloc_(2);
static inline void freep(void *p) {
free(*(void**) p);
@@ -84,6 +87,13 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, si
return memdup(p, size * need);
}
+_alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
+ return NULL;
+
+ return memdup_suffix0(p, size * need);
+}
+
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c
index d1c9695973..24a6c8a936 100644
--- a/src/basic/audit-util.c
+++ b/src/basic/audit-util.c
@@ -54,7 +54,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id) {
if (r < 0)
return r;
- if (u == AUDIT_SESSION_INVALID || u <= 0)
+ if (!audit_session_is_valid(u))
return -ENODATA;
*id = u;
@@ -81,7 +81,7 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
if (r < 0)
return r;
- *uid = (uid_t) u;
+ *uid = u;
return 0;
}
diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h
index e048503991..3088951326 100644
--- a/src/basic/audit-util.h
+++ b/src/basic/audit-util.h
@@ -29,3 +29,7 @@ int audit_session_from_pid(pid_t pid, uint32_t *id);
int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
bool use_audit(void);
+
+static inline bool audit_session_is_valid(uint32_t id) {
+ return id > 0 && id != AUDIT_SESSION_INVALID;
+}
diff --git a/src/basic/barrier.c b/src/basic/barrier.c
index 2da633b311..0c44e47b12 100644
--- a/src/basic/barrier.c
+++ b/src/basic/barrier.c
@@ -171,7 +171,7 @@ void barrier_set_role(Barrier *b, unsigned int role) {
int fd;
assert(b);
- assert(role == BARRIER_PARENT || role == BARRIER_CHILD);
+ assert(IN_SET(role, BARRIER_PARENT, BARRIER_CHILD));
/* make sure this is only called once */
assert(b->pipe[0] >= 0 && b->pipe[1] >= 0);
diff --git a/src/basic/barrier.h b/src/basic/barrier.h
index 6347fddc4d..fbc2d9d98d 100644
--- a/src/basic/barrier.h
+++ b/src/basic/barrier.h
@@ -70,11 +70,11 @@ bool barrier_sync_next(Barrier *b);
bool barrier_sync(Barrier *b);
static inline bool barrier_i_aborted(Barrier *b) {
- return b->barriers == BARRIER_I_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers, BARRIER_I_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_they_aborted(Barrier *b) {
- return b->barriers == BARRIER_THEY_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers, BARRIER_THEY_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_we_aborted(Barrier *b) {
@@ -82,7 +82,8 @@ static inline bool barrier_we_aborted(Barrier *b) {
}
static inline bool barrier_is_aborted(Barrier *b) {
- return b->barriers == BARRIER_I_ABORTED || b->barriers == BARRIER_THEY_ABORTED || b->barriers == BARRIER_WE_ABORTED;
+ return IN_SET(b->barriers,
+ BARRIER_I_ABORTED, BARRIER_THEY_ABORTED, BARRIER_WE_ABORTED);
}
static inline bool barrier_place_and_sync(Barrier *b) {
diff --git a/src/basic/blkid-util.h b/src/basic/blkid-util.h
index 1b9cace040..53340ec6f3 100644
--- a/src/basic/blkid-util.h
+++ b/src/basic/blkid-util.h
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
#include <blkid.h>
#endif
#include "util.h"
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
#define _cleanup_blkid_free_probe_ _cleanup_(blkid_free_probep)
#endif
diff --git a/src/basic/bpf-program.c b/src/basic/bpf-program.c
new file mode 100644
index 0000000000..ce6f9e4409
--- /dev/null
+++ b/src/basic/bpf-program.c
@@ -0,0 +1,183 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "bpf-program.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+
+ p = new0(BPFProgram, 1);
+ if (!p)
+ return log_oom();
+
+ p->prog_type = prog_type;
+ p->kernel_fd = -1;
+
+ *ret = p;
+ p = NULL;
+ return 0;
+}
+
+BPFProgram *bpf_program_unref(BPFProgram *p) {
+ if (!p)
+ return NULL;
+
+ safe_close(p->kernel_fd);
+ free(p->instructions);
+
+ return mfree(p);
+}
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *instructions, size_t count) {
+
+ assert(p);
+
+ if (!GREEDY_REALLOC(p->instructions, p->allocated, p->n_instructions + count))
+ return -ENOMEM;
+
+ memcpy(p->instructions + p->n_instructions, instructions, sizeof(struct bpf_insn) * count);
+ p->n_instructions += count;
+
+ return 0;
+}
+
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size) {
+ union bpf_attr attr;
+
+ assert(p);
+
+ if (p->kernel_fd >= 0)
+ return -EBUSY;
+
+ attr = (union bpf_attr) {
+ .prog_type = p->prog_type,
+ .insns = PTR_TO_UINT64(p->instructions),
+ .insn_cnt = p->n_instructions,
+ .license = PTR_TO_UINT64("GPL"),
+ .log_buf = PTR_TO_UINT64(log_buf),
+ .log_level = !!log_buf,
+ .log_size = log_size,
+ };
+
+ p->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
+ if (p->kernel_fd < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path, uint32_t flags) {
+ _cleanup_close_ int fd = -1;
+ union bpf_attr attr;
+
+ assert(p);
+ assert(type >= 0);
+ assert(path);
+
+ fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ attr = (union bpf_attr) {
+ .attach_type = type,
+ .target_fd = fd,
+ .attach_bpf_fd = p->kernel_fd,
+ .attach_flags = flags,
+ };
+
+ if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_program_cgroup_detach(int type, const char *path) {
+ _cleanup_close_ int fd = -1;
+ union bpf_attr attr;
+
+ assert(path);
+
+ fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ attr = (union bpf_attr) {
+ .attach_type = type,
+ .target_fd = fd,
+ };
+
+ if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags) {
+ union bpf_attr attr = {
+ .map_type = type,
+ .key_size = key_size,
+ .value_size = value_size,
+ .max_entries = max_entries,
+ .map_flags = flags,
+ };
+ int fd;
+
+ fd = bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+int bpf_map_update_element(int fd, const void *key, void *value) {
+
+ union bpf_attr attr = {
+ .map_fd = fd,
+ .key = PTR_TO_UINT64(key),
+ .value = PTR_TO_UINT64(value),
+ };
+
+ if (bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int bpf_map_lookup_element(int fd, const void *key, void *value) {
+
+ union bpf_attr attr = {
+ .map_fd = fd,
+ .key = PTR_TO_UINT64(key),
+ .value = PTR_TO_UINT64(value),
+ };
+
+ if (bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/basic/bpf-program.h b/src/basic/bpf-program.h
new file mode 100644
index 0000000000..35a41ffc44
--- /dev/null
+++ b/src/basic/bpf-program.h
@@ -0,0 +1,55 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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/>.
+
+ [Except for the stuff copy/pasted from the kernel sources, see below]
+***/
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+
+#include "list.h"
+#include "macro.h"
+
+typedef struct BPFProgram BPFProgram;
+
+struct BPFProgram {
+ int kernel_fd;
+ uint32_t prog_type;
+
+ size_t n_instructions;
+ size_t allocated;
+ struct bpf_insn *instructions;
+};
+
+int bpf_program_new(uint32_t prog_type, BPFProgram **ret);
+BPFProgram *bpf_program_unref(BPFProgram *p);
+
+int bpf_program_add_instructions(BPFProgram *p, const struct bpf_insn *insn, size_t count);
+int bpf_program_load_kernel(BPFProgram *p, char *log_buf, size_t log_size);
+
+int bpf_program_cgroup_attach(BPFProgram *p, int type, const char *path, uint32_t flags);
+int bpf_program_cgroup_detach(int type, const char *path);
+
+int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
+int bpf_map_update_element(int fd, const void *key, void *value);
+int bpf_map_lookup_element(int fd, const void *key, void *value);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BPFProgram*, bpf_program_unref);
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 5505499312..c2061addd1 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -32,7 +32,7 @@
#include <sys/sysmacros.h>
#include <unistd.h>
-#ifdef HAVE_LINUX_BTRFS_H
+#if HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
diff --git a/src/basic/build.h b/src/basic/build.h
index 3223915da6..9aaa6e3dae 100644
--- a/src/basic/build.h
+++ b/src/basic/build.h
@@ -19,121 +19,121 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_PAM
+#if HAVE_PAM
#define _PAM_FEATURE_ "+PAM"
#else
#define _PAM_FEATURE_ "-PAM"
#endif
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#define _AUDIT_FEATURE_ "+AUDIT"
#else
#define _AUDIT_FEATURE_ "-AUDIT"
#endif
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#define _SELINUX_FEATURE_ "+SELINUX"
#else
#define _SELINUX_FEATURE_ "-SELINUX"
#endif
-#ifdef HAVE_APPARMOR
+#if HAVE_APPARMOR
#define _APPARMOR_FEATURE_ "+APPARMOR"
#else
#define _APPARMOR_FEATURE_ "-APPARMOR"
#endif
-#ifdef HAVE_IMA
+#if ENABLE_IMA
#define _IMA_FEATURE_ "+IMA"
#else
#define _IMA_FEATURE_ "-IMA"
#endif
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
#define _SMACK_FEATURE_ "+SMACK"
#else
#define _SMACK_FEATURE_ "-SMACK"
#endif
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
#define _SYSVINIT_FEATURE_ "+SYSVINIT"
#else
#define _SYSVINIT_FEATURE_ "-SYSVINIT"
#endif
-#ifdef HAVE_UTMP
+#if ENABLE_UTMP
#define _UTMP_FEATURE_ "+UTMP"
#else
#define _UTMP_FEATURE_ "-UTMP"
#endif
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
#else
#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
#endif
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#define _GCRYPT_FEATURE_ "+GCRYPT"
#else
#define _GCRYPT_FEATURE_ "-GCRYPT"
#endif
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
#define _GNUTLS_FEATURE_ "+GNUTLS"
#else
#define _GNUTLS_FEATURE_ "-GNUTLS"
#endif
-#ifdef HAVE_ACL
+#if HAVE_ACL
#define _ACL_FEATURE_ "+ACL"
#else
#define _ACL_FEATURE_ "-ACL"
#endif
-#ifdef HAVE_XZ
+#if HAVE_XZ
#define _XZ_FEATURE_ "+XZ"
#else
#define _XZ_FEATURE_ "-XZ"
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
#define _LZ4_FEATURE_ "+LZ4"
#else
#define _LZ4_FEATURE_ "-LZ4"
#endif
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#define _SECCOMP_FEATURE_ "+SECCOMP"
#else
#define _SECCOMP_FEATURE_ "-SECCOMP"
#endif
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
#define _BLKID_FEATURE_ "+BLKID"
#else
#define _BLKID_FEATURE_ "-BLKID"
#endif
-#ifdef HAVE_ELFUTILS
+#if HAVE_ELFUTILS
#define _ELFUTILS_FEATURE_ "+ELFUTILS"
#else
#define _ELFUTILS_FEATURE_ "-ELFUTILS"
#endif
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
#define _KMOD_FEATURE_ "+KMOD"
#else
#define _KMOD_FEATURE_ "-KMOD"
#endif
-#ifdef HAVE_LIBIDN2
+#if HAVE_LIBIDN2
#define _IDN2_FEATURE_ "+IDN2"
#else
#define _IDN2_FEATURE_ "-IDN2"
#endif
-#ifdef HAVE_LIBIDN
+#if HAVE_LIBIDN
#define _IDN_FEATURE_ "+IDN"
#else
#define _IDN_FEATURE_ "-IDN"
diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h
index 62fb2c450c..600268b767 100644
--- a/src/basic/bus-label.h
+++ b/src/basic/bus-label.h
@@ -23,9 +23,11 @@
#include <stdlib.h>
#include <string.h>
+#include "string-util.h"
+
char *bus_label_escape(const char *s);
char *bus_label_unescape_n(const char *f, size_t l);
static inline char *bus_label_unescape(const char *f) {
- return bus_label_unescape_n(f, f ? strlen(f) : 0);
+ return bus_label_unescape_n(f, strlen_ptr(f));
}
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 204120ee0e..1fc9e9b154 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <time.h>
#include "alloc-util.h"
@@ -33,6 +34,7 @@
#include "macro.h"
#include "parse-util.h"
#include "string-util.h"
+#include "time-util.h"
#define BITS_WEEKDAYS 127
#define MIN_YEAR 1970
@@ -59,6 +61,7 @@ void calendar_spec_free(CalendarSpec *c) {
free_chain(c->hour);
free_chain(c->minute);
free_chain(c->microsecond);
+ free(c->timezone);
free(c);
}
@@ -257,19 +260,19 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
if (l < 0) {
if (need_comma)
- fputc(',', f);
+ fputc_unlocked(',', f);
else
need_comma = true;
- fputs(days[x], f);
+ fputs_unlocked(days[x], f);
l = x;
}
} else if (l >= 0) {
if (x > l + 1) {
- fputs(x > l + 2 ? ".." : ",", f);
- fputs(days[x-1], f);
+ fputs_unlocked(x > l + 2 ? ".." : ",", f);
+ fputs_unlocked(days[x-1], f);
}
l = -1;
@@ -277,8 +280,8 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
}
if (l >= 0 && x > l + 1) {
- fputs(x > l + 2 ? ".." : ",", f);
- fputs(days[x-1], f);
+ fputs_unlocked(x > l + 2 ? ".." : ",", f);
+ fputs_unlocked(days[x-1], f);
}
}
@@ -288,12 +291,12 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us
assert(f);
if (!c) {
- fputc('*', f);
+ fputc_unlocked('*', f);
return;
}
if (usec && c->start == 0 && c->repeat == USEC_PER_SEC && !c->next) {
- fputc('*', f);
+ fputc_unlocked('*', f);
return;
}
@@ -314,7 +317,7 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us
fprintf(f, ".%06i", c->repeat % d);
if (c->next) {
- fputc(',', f);
+ fputc_unlocked(',', f);
format_chain(f, space, c->next, usec);
}
}
@@ -334,32 +337,35 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
format_weekdays(f, c);
- fputc(' ', f);
+ fputc_unlocked(' ', f);
}
format_chain(f, 4, c->year, false);
- fputc('-', f);
+ fputc_unlocked('-', f);
format_chain(f, 2, c->month, false);
- fputc(c->end_of_month ? '~' : '-', f);
+ fputc_unlocked(c->end_of_month ? '~' : '-', f);
format_chain(f, 2, c->day, false);
- fputc(' ', f);
+ fputc_unlocked(' ', f);
format_chain(f, 2, c->hour, false);
- fputc(':', f);
+ fputc_unlocked(':', f);
format_chain(f, 2, c->minute, false);
- fputc(':', f);
+ fputc_unlocked(':', f);
format_chain(f, 2, c->microsecond, true);
if (c->utc)
- fputs(" UTC", f);
- else if (IN_SET(c->dst, 0, 1)) {
+ fputs_unlocked(" UTC", f);
+ else if (c->timezone != NULL) {
+ fputc_unlocked(' ', f);
+ fputs_unlocked(c->timezone, f);
+ } else if (IN_SET(c->dst, 0, 1)) {
/* If daylight saving is explicitly on or off, let's show the used timezone. */
tzset();
if (!isempty(tzname[c->dst])) {
- fputc(' ', f);
- fputs(tzname[c->dst], f);
+ fputc_unlocked(' ', f);
+ fputs_unlocked(tzname[c->dst], f);
}
}
@@ -415,11 +421,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
skip = strlen(day_nr[i].name);
- if ((*p)[skip] != '-' &&
- (*p)[skip] != '.' &&
- (*p)[skip] != ',' &&
- (*p)[skip] != ' ' &&
- (*p)[skip] != 0)
+ if (!IN_SET((*p)[skip], 0, '-', '.', ',', ' '))
return -EINVAL;
c->weekdays_bits |= 1 << day_nr[i].nr;
@@ -478,7 +480,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
}
/* Allow a trailing comma but not an open range */
- if (**p == 0 || **p == ' ') {
+ if (IN_SET(**p, 0, ' ')) {
*p += strspn(*p, " ");
return l < 0 ? 0 : -EINVAL;
}
@@ -638,7 +640,7 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
return -ERANGE;
}
- if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != '~' && *e != ':')
+ if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
return -EINVAL;
cc = new0(CalendarComponent, 1);
@@ -735,7 +737,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
return r;
/* Already the end? A ':' as separator? In that case this was a time, not a date */
- if (*t == 0 || *t == ':') {
+ if (IN_SET(*t, 0, ':')) {
free_chain(first);
return 0;
}
@@ -755,7 +757,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
/* Got two parts, hence it's month and day */
- if (*t == ' ' || *t == 0) {
+ if (IN_SET(*t, 0, ' ')) {
*p = t + strspn(t, " ");
c->month = first;
c->day = second;
@@ -783,7 +785,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
}
/* Got three parts, hence it is year, month and day */
- if (*t == ' ' || *t == 0) {
+ if (IN_SET(*t, 0, ' ')) {
*p = t + strspn(t, " ");
c->year = first;
c->month = second;
@@ -888,6 +890,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (!c)
return -ENOMEM;
c->dst = -1;
+ c->timezone = NULL;
utc = endswith_no_case(p, " UTC");
if (utc) {
@@ -919,6 +922,19 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (IN_SET(j, 0, 1)) {
p = strndupa(p, e - p - 1);
c->dst = j;
+ } else {
+ const char *last_space;
+
+ last_space = strrchr(p, ' ');
+ if (last_space != NULL && timezone_is_valid(last_space + 1)) {
+ c->timezone = strdup(last_space + 1);
+ if (!c->timezone) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ p = strndupa(p, last_space - p);
+ }
}
}
@@ -1293,7 +1309,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
}
}
-int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+static int calendar_spec_next_usec_impl(const CalendarSpec *spec, usec_t usec, usec_t *next) {
struct tm tm;
time_t t;
int r;
@@ -1321,3 +1337,58 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
*next = (usec_t) t * USEC_PER_SEC + tm_usec;
return 0;
}
+
+typedef struct SpecNextResult {
+ usec_t next;
+ int return_value;
+} SpecNextResult;
+
+int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+ pid_t pid;
+ SpecNextResult *shared;
+ SpecNextResult tmp;
+ int r;
+
+ if (isempty(spec->timezone))
+ return calendar_spec_next_usec_impl(spec, usec, next);
+
+ shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (shared == MAP_FAILED)
+ return negative_errno();
+
+ pid = fork();
+
+ if (pid == -1) {
+ int fork_errno = errno;
+ (void) munmap(shared, sizeof *shared);
+ return -fork_errno;
+ }
+
+ if (pid == 0) {
+ if (setenv("TZ", spec->timezone, 1) != 0) {
+ shared->return_value = negative_errno();
+ _exit(EXIT_FAILURE);
+ }
+
+ tzset();
+
+ shared->return_value = calendar_spec_next_usec_impl(spec, usec, &shared->next);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate(pid, NULL);
+ if (r < 0) {
+ (void) munmap(shared, sizeof *shared);
+ return r;
+ }
+
+ tmp = *shared;
+ if (munmap(shared, sizeof *shared) != 0)
+ return negative_errno();
+
+ if (tmp.return_value == 0)
+ *next = tmp.next;
+
+ return tmp.return_value;
+}
diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h
index 3d8798de0b..8888251705 100644
--- a/src/basic/calendarspec.h
+++ b/src/basic/calendarspec.h
@@ -40,6 +40,7 @@ typedef struct CalendarSpec {
bool end_of_month;
bool utc;
int dst;
+ char *timezone;
CalendarComponent *year;
CalendarComponent *month;
diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c
index d68cc78d05..2e9b2d9a55 100644
--- a/src/basic/cap-list.c
+++ b/src/basic/cap-list.c
@@ -20,7 +20,10 @@
#include <errno.h>
#include <string.h>
+#include "alloc-util.h"
+#include "capability-util.h"
#include "cap-list.h"
+#include "extract-word.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
@@ -64,3 +67,67 @@ int capability_from_name(const char *name) {
int capability_list_length(void) {
return (int) ELEMENTSOF(capability_names);
}
+
+int capability_set_to_string_alloc(uint64_t set, char **s) {
+ _cleanup_free_ char *str = NULL;
+ unsigned long i;
+ size_t allocated = 0, n = 0;
+
+ assert(s);
+
+ for (i = 0; i < cap_last_cap(); i++)
+ if (set & (UINT64_C(1) << i)) {
+ const char *p;
+ size_t add;
+
+ p = capability_to_name(i);
+ if (!p)
+ return -EINVAL;
+
+ add = strlen(p);
+
+ if (!GREEDY_REALLOC(str, allocated, n + add + 2))
+ return -ENOMEM;
+
+ strcpy(mempcpy(str + n, p, add), " ");
+ n += add + 1;
+ }
+
+ if (!GREEDY_REALLOC(str, allocated, n + 1))
+ return -ENOMEM;
+
+ str[n > 0 ? n - 1 : 0] = '\0'; /* truncate the last space, if it's there */
+
+ *s = str;
+ str = NULL;
+
+ return 0;
+}
+
+int capability_set_from_string(const char *s, uint64_t *set) {
+ uint64_t val = 0;
+ const char *p;
+
+ assert(set);
+
+ for (p = s;;) {
+ _cleanup_free_ char *word = NULL;
+ int r;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ r = capability_from_name(word);
+ if (r < 0)
+ continue;
+
+ val |= ((uint64_t) UINT64_C(1)) << (uint64_t) r;
+ }
+
+ *set = val;
+
+ return 0;
+}
diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h
index c1f6b94ad3..f9f6b70d80 100644
--- a/src/basic/cap-list.h
+++ b/src/basic/cap-list.h
@@ -22,3 +22,6 @@
const char *capability_to_name(int id);
int capability_from_name(const char *name);
int capability_list_length(void);
+
+int capability_set_to_string_alloc(uint64_t set, char **s);
+int capability_set_from_string(const char *s, uint64_t *set);
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index c3de20a0e8..96c2e992bd 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -151,7 +151,7 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
}
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
- _cleanup_cap_free_ cap_t after_cap = NULL;
+ _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
cap_flag_value_t fv;
unsigned long i;
int r;
@@ -161,71 +161,80 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
* executing init!), so get it back temporarily so that we can
* call PR_CAPBSET_DROP. */
- after_cap = cap_get_proc();
- if (!after_cap)
+ before_cap = cap_get_proc();
+ if (!before_cap)
return -errno;
- if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
+ if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
return -errno;
if (fv != CAP_SET) {
_cleanup_cap_free_ cap_t temp_cap = NULL;
static const cap_value_t v = CAP_SETPCAP;
- temp_cap = cap_dup(after_cap);
- if (!temp_cap) {
- r = -errno;
- goto finish;
- }
+ temp_cap = cap_dup(before_cap);
+ if (!temp_cap)
+ return -errno;
- if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
- r = -errno;
- goto finish;
- }
+ if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0)
+ return -errno;
- if (cap_set_proc(temp_cap) < 0) {
- r = -errno;
- goto finish;
- }
+ if (cap_set_proc(temp_cap) < 0)
+ log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
+
+ /* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
+ * we'll fail later, when we actually intend to drop some capabilities. */
}
+ after_cap = cap_dup(before_cap);
+ if (!after_cap)
+ return -errno;
+
for (i = 0; i <= cap_last_cap(); i++) {
+ cap_value_t v;
- if (!(keep & (UINT64_C(1) << i))) {
- cap_value_t v;
+ if ((keep & (UINT64_C(1) << i)))
+ continue;
- /* Drop it from the bounding set */
- if (prctl(PR_CAPBSET_DROP, i) < 0) {
- r = -errno;
+ /* Drop it from the bounding set */
+ if (prctl(PR_CAPBSET_DROP, i) < 0) {
+ r = -errno;
+
+ /* If dropping the capability failed, let's see if we didn't have it in the first place. If so,
+ * continue anyway, as dropping a capability we didn't have in the first place doesn't really
+ * matter anyway. */
+ if (prctl(PR_CAPBSET_READ, i) != 0)
goto finish;
- }
- v = (cap_value_t) i;
+ }
+ v = (cap_value_t) i;
+
+ /* Also drop it from the inheritable set, so
+ * that anything we exec() loses the
+ * capability for good. */
+ if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
+ r = -errno;
+ goto finish;
+ }
- /* Also drop it from the inheritable set, so
- * that anything we exec() loses the
- * capability for good. */
- if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) {
+ /* If we shall apply this right now drop it
+ * also from our own capability sets. */
+ if (right_now) {
+ if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
+ cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
r = -errno;
goto finish;
}
-
- /* If we shall apply this right now drop it
- * also from our own capability sets. */
- if (right_now) {
- if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 ||
- cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) {
- r = -errno;
- goto finish;
- }
- }
}
}
r = 0;
finish:
- if (cap_set_proc(after_cap) < 0)
- return -errno;
+ if (cap_set_proc(after_cap) < 0) {
+ /* If there are no actual changes anyway then let's ignore this error. */
+ if (cap_compare(before_cap, after_cap) != 0)
+ r = -errno;
+ }
return r;
}
@@ -361,3 +370,18 @@ int drop_capability(cap_value_t cv) {
return 0;
}
+
+bool ambient_capabilities_supported(void) {
+ static int cache = -1;
+
+ if (cache >= 0)
+ return cache;
+
+ /* If PR_CAP_AMBIENT returns something valid, or an unexpected error code we assume that ambient caps are
+ * available. */
+
+ cache = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_KILL, 0, 0) >= 0 ||
+ !IN_SET(errno, EINVAL, EOPNOTSUPP, ENOSYS);
+
+ return cache;
+}
diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h
index 35a896e229..3dc9429153 100644
--- a/src/basic/capability-util.h
+++ b/src/basic/capability-util.h
@@ -55,3 +55,5 @@ static inline bool cap_test_all(uint64_t caps) {
m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
return (caps & m) == m;
}
+
+bool ambient_capabilities_supported(void);
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 75dfec33fb..94b11a26e9 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -103,9 +103,12 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
return 1;
}
-int cg_read_event(const char *controller, const char *path, const char *event,
- char **val)
-{
+int cg_read_event(
+ const char *controller,
+ const char *path,
+ const char *event,
+ char **val) {
+
_cleanup_free_ char *events = NULL, *content = NULL;
char *p, *line;
int r;
@@ -255,7 +258,7 @@ int cg_kill(
return -ENOMEM;
}
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
@@ -371,7 +374,7 @@ int cg_kill_recursive(
if (flags & CGROUP_REMOVE) {
r = cg_rmdir(controller, path);
- if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
+ if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
return r;
}
@@ -399,7 +402,7 @@ int cg_migrate(
if (!s)
return -ENOMEM;
- my_pid = getpid();
+ my_pid = getpid_cached();
do {
_cleanup_fclose_ FILE *f = NULL;
@@ -506,7 +509,7 @@ int cg_migrate_recursive(
if (flags & CGROUP_REMOVE) {
r = cg_rmdir(cfrom, pfrom);
- if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
+ if (r < 0 && ret >= 0 && !IN_SET(r, -ENOENT, -EBUSY))
return r;
}
@@ -825,7 +828,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
return r;
if (pid == 0)
- pid = getpid();
+ pid = getpid_cached();
xsprintf(c, PID_FMT "\n", pid);
@@ -902,7 +905,7 @@ int cg_set_group_access(
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set group access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set group access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
@@ -915,7 +918,7 @@ int cg_set_task_access(
uid_t uid,
gid_t gid) {
- _cleanup_free_ char *fs = NULL, *procs = NULL;
+ _cleanup_free_ char *fs = NULL;
int r;
assert(path);
@@ -926,6 +929,7 @@ int cg_set_task_access(
if (mode != MODE_INVALID)
mode &= 0666;
+ /* For both the legacy and unified hierarchies, "cgroup.procs" is the main entry point for PIDs */
r = cg_get_path(controller, path, "cgroup.procs", &fs);
if (r < 0)
return r;
@@ -938,19 +942,48 @@ int cg_set_task_access(
if (r < 0)
return r;
if (r == 0) {
- /* Compatibility, Always keep values for "tasks" in sync with
- * "cgroup.procs" */
- if (cg_get_path(controller, path, "tasks", &procs) >= 0)
- (void) chmod_and_chown(procs, mode, uid, gid);
+ const char *fn;
+
+ /* Compatibility: on cgroupsv1 always keep values for the legacy files "tasks" and
+ * "cgroup.clone_children" in sync with "cgroup.procs". Since this is legacy stuff, we don't care if
+ * this fails. */
+
+ FOREACH_STRING(fn,
+ "tasks",
+ "cgroup.clone_children") {
+
+ fs = mfree(fs);
+
+ r = cg_get_path(controller, path, fn, &fs);
+ if (r < 0)
+ log_debug_errno(r, "Failed to get path for %s of %s, ignoring: %m", fn, path);
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ log_debug_errno(r, "Failed to to change ownership/access mode for %s of %s, ignoring: %m", fn, path);
+ }
+ } else {
+ /* On the unified controller, we want to permit subtree controllers too. */
+
+ fs = mfree(fs);
+ r = cg_get_path(controller, path, "cgroup.subtree_control", &fs);
+ if (r < 0)
+ return r;
+
+ r = chmod_and_chown(fs, mode, uid, gid);
+ if (r < 0)
+ return r;
}
r = cg_hybrid_unified();
if (r < 0)
return r;
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+ /* Always propagate access mode from unified to legacy controller */
+
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
if (r < 0)
- log_warning_errno(r, "Failed to set task access on compat systemd cgroup %s: %m", path);
+ log_debug_errno(r, "Failed to set task access on compatibility systemd cgroup %s, ignoring: %m", path);
}
return 0;
@@ -1853,9 +1886,7 @@ char *cg_escape(const char *p) {
/* The return value of this function (unlike cg_unescape())
* needs free()! */
- if (p[0] == 0 ||
- p[0] == '_' ||
- p[0] == '.' ||
+ if (IN_SET(p[0], 0, '_', '.') ||
streq(p, "notify_on_release") ||
streq(p, "release_agent") ||
streq(p, "tasks") ||
@@ -1921,7 +1952,7 @@ bool cg_controller_is_valid(const char *p) {
if (s)
p = s;
- if (*p == 0 || *p == '_')
+ if (IN_SET(*p, 0, '_'))
return false;
for (t = p; *t; t++)
@@ -1973,7 +2004,7 @@ int cg_slice_to_path(const char *unit, char **ret) {
char n[dash - p + sizeof(".slice")];
/* Don't allow trailing or double dashes */
- if (dash[1] == 0 || dash[1] == '-')
+ if (IN_SET(dash[1], 0, '-'))
return -EINVAL;
strcpy(stpncpy(n, p, dash - p), ".slice");
@@ -2329,7 +2360,6 @@ int cg_mask_supported(CGroupMask *ret) {
int cg_kernel_controllers(Set *controllers) {
_cleanup_fclose_ FILE *f = NULL;
- char buf[LINE_MAX];
int r;
assert(controllers);
@@ -2347,7 +2377,7 @@ int cg_kernel_controllers(Set *controllers) {
}
/* Ignore the header line */
- (void) fgets(buf, sizeof(buf), f);
+ (void) read_line(f, (size_t) -1, NULL);
for (;;) {
char *controller;
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index b8f0f5d03d..907d1350fe 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -32,11 +32,12 @@
#include "macro.h"
#include "missing.h"
#include "path-util.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
+static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned flags, const char *path) {
_cleanup_closedir_ DIR *dir = NULL;
const char *dirpath;
struct dirent *de;
@@ -56,8 +57,40 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
FOREACH_DIRENT(de, dir, return -errno) {
char *p;
- if (!dirent_is_file_with_suffix(de, suffix))
+ if (!dirent_is_file_with_suffix(de, suffix)) {
+ log_debug("Ignoring %s/%s, because it's not a regular file with suffix %s.", dirpath, de->d_name, strna(suffix));
continue;
+ }
+
+ if (flags & CONF_FILES_EXECUTABLE) {
+ struct stat st;
+
+ /* As requested: check if the file is marked exectuable. Note that we don't check access(X_OK)
+ * here, as we care about whether the file is marked executable at all, and not whether it is
+ * executable for us, because if such errors are stuff we should log about. */
+
+ if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
+ log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", dirpath, de->d_name);
+ continue;
+ }
+
+ if (!null_or_empty(&st)) {
+ /* A mask is a symlink to /dev/null or an empty file. It does not even
+ * have to be executable. Other entries must be regular executable files
+ * or symlinks to them. */
+ if (S_ISREG(st.st_mode)) {
+ if ((st.st_mode & 0111) == 0) { /* not executable */
+ log_debug("Ignoring %s/%s, as it is not marked executable.",
+ dirpath, de->d_name);
+ continue;
+ }
+ } else {
+ log_debug("Ignoring %s/%s, as it is neither a regular file nor a mask.",
+ dirpath, de->d_name);
+ continue;
+ }
+ }
+ }
p = strjoin(dirpath, "/", de->d_name);
if (!p)
@@ -87,7 +120,7 @@ static int base_cmp(const void *a, const void *b) {
return strcmp(basename(s1), basename(s2));
}
-static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
+static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
char **files, **p;
int r;
@@ -103,7 +136,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
return -ENOMEM;
STRV_FOREACH(p, dirs) {
- r = files_add(fh, root, *p, suffix);
+ r = files_add(fh, suffix, root, flags, *p);
if (r == -ENOMEM)
return r;
if (r < 0)
@@ -120,7 +153,7 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
return 0;
}
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) {
+int conf_files_list_strv(char ***strv, const char *suffix, const char *root, unsigned flags, const char* const* dirs) {
_cleanup_strv_free_ char **copy = NULL;
assert(strv);
@@ -129,10 +162,10 @@ int conf_files_list_strv(char ***strv, const char *suffix, const char *root, con
if (!copy)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, copy);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, copy);
}
-int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
+int conf_files_list(char ***strv, const char *suffix, const char *root, unsigned flags, const char *dir, ...) {
_cleanup_strv_free_ char **dirs = NULL;
va_list ap;
@@ -145,10 +178,10 @@ int conf_files_list(char ***strv, const char *suffix, const char *root, const ch
if (!dirs)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, dirs);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
}
-int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, unsigned flags, const char *d) {
_cleanup_strv_free_ char **dirs = NULL;
assert(strv);
@@ -157,5 +190,5 @@ int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, c
if (!dirs)
return -ENOMEM;
- return conf_files_list_strv_internal(strv, suffix, root, dirs);
+ return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
}
diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h
index e00e0e81fb..20ecf6e5f1 100644
--- a/src/basic/conf-files.h
+++ b/src/basic/conf-files.h
@@ -20,6 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int conf_files_list(char ***ret, const char *suffix, const char *root, const char *dir, ...);
-int conf_files_list_strv(char ***ret, const char *suffix, const char *root, const char* const* dirs);
-int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, const char *dirs);
+enum {
+ CONF_FILES_EXECUTABLE = 1,
+};
+
+int conf_files_list(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dir, ...);
+int conf_files_list_strv(char ***ret, const char *suffix, const char *root, unsigned flags, const char* const* dirs);
+int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, unsigned flags, const char *dirs);
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
index 95ed6928ff..aec0edc3dc 100644
--- a/src/basic/cpu-set-util.c
+++ b/src/basic/cpu-set-util.c
@@ -112,3 +112,49 @@ int parse_cpu_set_and_warn(
return (int) ncpus;
}
+
+int parse_cpu_set(
+ const char *rvalue,
+ cpu_set_t **cpu_set) {
+
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ unsigned ncpus = 0;
+
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ unsigned cpu, cpu_lower, cpu_upper;
+ int r;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ if (!c) {
+ c = cpu_set_malloc(&ncpus);
+ if (!c)
+ return -ENOMEM;
+ }
+
+ r = parse_range(word, &cpu_lower, &cpu_upper);
+ if (r < 0)
+ return r;
+ if (cpu_lower >= ncpus || cpu_upper >= ncpus)
+ return -EINVAL;
+
+ if (cpu_lower <= cpu_upper)
+ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ }
+
+ /* On success, sets *cpu_set and returns ncpus for the system. */
+ if (c) {
+ *cpu_set = c;
+ c = NULL;
+ }
+
+ return (int) ncpus;
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
index 6f49d9afb0..9b08ba0a67 100644
--- a/src/basic/cpu-set-util.h
+++ b/src/basic/cpu-set-util.h
@@ -30,3 +30,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
+int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set);
diff --git a/src/basic/def.h b/src/basic/def.h
index b1a3bc190b..c04e58b57a 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -43,7 +43,7 @@
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
#define KBD_KEYMAP_DIRS \
"/usr/share/keymaps/\0" \
"/usr/share/kbd/keymaps/\0" \
@@ -57,10 +57,8 @@
#endif
#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/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 DEFAULT_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 PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
@@ -70,7 +68,7 @@
#define NOTIFY_FD_MAX 768
#define NOTIFY_BUFFER_MAX PIPE_BUF
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
# define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0"
#else
# define _CONF_PATHS_SPLIT_USR(n)
@@ -86,3 +84,5 @@
"/usr/local/lib/" n "\0" \
"/usr/lib/" n "\0" \
_CONF_PATHS_SPLIT_USR(n)
+
+#define LONG_LINE_MAX (1U*1024U*1024U)
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 56e7b6fd8c..fa42edfa96 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -707,7 +707,7 @@ char **replace_env_argv(char **argv, char **env) {
STRV_FOREACH(i, argv) {
/* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{' && (*i)[1] != '$') {
+ if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
char *e;
char **w, **m = NULL;
unsigned q;
@@ -769,6 +769,16 @@ int getenv_bool(const char *p) {
return parse_boolean(e);
}
+int getenv_bool_secure(const char *p) {
+ const char *e;
+
+ e = secure_getenv(p);
+ if (!e)
+ return -ENXIO;
+
+ return parse_boolean(e);
+}
+
int serialize_environment(FILE *f, char **environment) {
char **e;
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index e88fa6aac0..d5da8cd67b 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -61,6 +61,7 @@ char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure
char *strv_env_get(char **x, const char *n) _pure_;
int getenv_bool(const char *p);
+int getenv_bool_secure(const char *p);
int serialize_environment(FILE *f, char **environment);
int deserialize_environment(char ***environment, const char *line);
diff --git a/src/basic/escape.c b/src/basic/escape.c
index 85e4b5282e..0a6122c64a 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -314,7 +314,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
/* Undoes C style string escaping, and optionally prefixes it. */
- pl = prefix ? strlen(prefix) : 0;
+ pl = strlen_ptr(prefix);
r = new(char, pl+length+1);
if (!r)
@@ -426,7 +426,7 @@ char *octescape(const char *s, size_t len) {
for (f = s, t = r; f < s + len; f++) {
- if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') {
+ if (*f < ' ' || *f >= 127 || IN_SET(*f, '\\', '"')) {
*(t++) = '\\';
*(t++) = '0' + (*f >> 6);
*(t++) = '0' + ((*f >> 3) & 8);
diff --git a/src/basic/exec-util.c b/src/basic/exec-util.c
index aced9e8e3d..ade8511466 100644
--- a/src/basic/exec-util.c
+++ b/src/basic/exec-util.c
@@ -111,7 +111,7 @@ static int do_execute(
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
- r = conf_files_list_strv(&paths, NULL, NULL, (const char* const*) directories);
+ r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
if (r < 0)
return r;
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 1e23c32c3f..7cfebbae72 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -140,9 +140,6 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_RUNTIME_DIRECTORY:
return "RUNTIME_DIRECTORY";
- case EXIT_MAKE_STARTER:
- return "MAKE_STARTER";
-
case EXIT_CHOWN:
return "CHOWN";
@@ -151,6 +148,18 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_KEYRING:
return "KEYRING";
+
+ case EXIT_STATE_DIRECTORY:
+ return "STATE_DIRECTORY";
+
+ case EXIT_CACHE_DIRECTORY:
+ return "CACHE_DIRECTORY";
+
+ case EXIT_LOGS_DIRECTORY:
+ return "LOGS_DIRECTORY";
+
+ case EXIT_CONFIGURATION_DIRECTORY:
+ return "CONFIGURATION_DIRECTORY";
}
}
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index d22b2c00e4..195b3bc486 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -79,10 +79,14 @@ enum {
EXIT_APPARMOR_PROFILE,
EXIT_ADDRESS_FAMILIES,
EXIT_RUNTIME_DIRECTORY,
- EXIT_MAKE_STARTER,
+ _EXIT_RESERVED2, /* used to be used by kdbus, don't reuse */
EXIT_CHOWN,
EXIT_SMACK_PROCESS_LABEL,
EXIT_KEYRING,
+ EXIT_STATE_DIRECTORY,
+ EXIT_CACHE_DIRECTORY,
+ EXIT_LOGS_DIRECTORY, /* 240 */
+ EXIT_CONFIGURATION_DIRECTORY,
};
typedef enum ExitStatusLevel {
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index 804f14c44c..f4ac526eb1 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -152,7 +152,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
- else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
+ else if (IN_SET(c, '\'', '"') && (flags & EXTRACT_QUOTES)) {
quote = c;
break;
} else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 30629200f1..4d2f047dca 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -31,6 +31,7 @@
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "util.h"
@@ -282,7 +283,7 @@ int same_fd(int a, int b) {
return true;
/* Try to use kcmp() if we have it. */
- pid = getpid();
+ pid = getpid_cached();
r = kcmp(pid, pid, KCMP_FILE, a, b);
if (r == 0)
return true;
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 9a185e3e60..9ee7a4af38 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -30,6 +30,7 @@
#include "alloc-util.h"
#include "ctype.h"
+#include "def.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
@@ -41,6 +42,7 @@
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "random-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -51,13 +53,17 @@
#define READ_FULL_BYTES_MAX (4U*1024U*1024U)
-int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts) {
+int write_string_stream_ts(
+ FILE *f,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
assert(f);
assert(line);
fputs(line, f);
- if (enforce_newline && !endswith(line, "\n"))
+ if (!(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n"))
fputc('\n', f);
if (ts) {
@@ -67,10 +73,18 @@ int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, stru
return -errno;
}
- return fflush_and_check(f);
+ if (flags & WRITE_STRING_FILE_SYNC)
+ return fflush_sync_and_check(f);
+ else
+ return fflush_and_check(f);
}
-static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
+static int write_string_file_atomic(
+ const char *fn,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
+
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
@@ -84,29 +98,41 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
(void) fchmod_umask(fileno(f), 0644);
- r = write_string_stream(f, line, enforce_newline);
- if (r >= 0) {
- if (rename(p, fn) < 0)
- r = -errno;
+ r = write_string_stream_ts(f, line, flags, ts);
+ if (r < 0)
+ goto fail;
+
+ if (rename(p, fn) < 0) {
+ r = -errno;
+ goto fail;
}
- if (r < 0)
- (void) unlink(p);
+ return 0;
+fail:
+ (void) unlink(p);
return r;
}
-int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts) {
+int write_string_file_ts(
+ const char *fn,
+ const char *line,
+ WriteStringFileFlags flags,
+ struct timespec *ts) {
+
_cleanup_fclose_ FILE *f = NULL;
int q, r;
assert(fn);
assert(line);
+ /* We don't know how to verify whether the file contents was already on-disk. */
+ assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
+
if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE);
- r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+ r = write_string_file_atomic(fn, line, flags, ts);
if (r < 0)
goto fail;
@@ -139,7 +165,7 @@ int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags
}
}
- r = write_string_stream_ts(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE), ts);
+ r = write_string_stream_ts(f, line, flags, ts);
if (r < 0)
goto fail;
@@ -163,7 +189,7 @@ fail:
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
- char t[LINE_MAX], *c;
+ int r;
assert(fn);
assert(line);
@@ -172,21 +198,8 @@ int read_one_line_file(const char *fn, char **line) {
if (!f)
return -errno;
- if (!fgets(t, sizeof(t), f)) {
-
- if (ferror(f))
- return errno > 0 ? -errno : -EIO;
-
- t[0] = 0;
- }
-
- c = strdup(t);
- if (!c)
- return -ENOMEM;
- truncate_nl(c);
-
- *line = c;
- return 0;
+ r = read_line(f, LONG_LINE_MAX, line);
+ return r < 0 ? r : 0;
}
int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
@@ -245,11 +258,11 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
if (st.st_size > READ_FULL_BYTES_MAX)
return -E2BIG;
- /* Start with the right file size, but be prepared for
- * files from /proc which generally report a file size
- * of 0 */
+ /* Start with the right file size, but be prepared for files from /proc which generally report a file
+ * size of 0. Note that we increase the size to read here by one, so that the first read attempt
+ * already makes us notice the EOF. */
if (st.st_size > 0)
- n = st.st_size;
+ n = st.st_size + 1;
}
l = 0;
@@ -262,12 +275,13 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
return -ENOMEM;
buf = t;
+ errno = 0;
k = fread(buf + l, 1, n - l, f);
if (k > 0)
l += k;
if (ferror(f))
- return -errno;
+ return errno > 0 ? -errno : -EIO;
if (feof(f))
break;
@@ -823,29 +837,29 @@ static void write_env_var(FILE *f, const char *v) {
p = strchr(v, '=');
if (!p) {
/* Fallback */
- fputs(v, f);
- fputc('\n', f);
+ fputs_unlocked(v, f);
+ fputc_unlocked('\n', f);
return;
}
p++;
- fwrite(v, 1, p-v, f);
+ fwrite_unlocked(v, 1, p-v, f);
if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) {
- fputc('\"', f);
+ fputc_unlocked('\"', f);
for (; *p; p++) {
if (strchr(SHELL_NEED_ESCAPE, *p))
- fputc('\\', f);
+ fputc_unlocked('\\', f);
- fputc(*p, f);
+ fputc_unlocked(*p, f);
}
- fputc('\"', f);
+ fputc_unlocked('\"', f);
} else
- fputs(p, f);
+ fputs_unlocked(p, f);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
int write_env_file(const char *fname, char **l) {
@@ -1125,6 +1139,21 @@ int fflush_and_check(FILE *f) {
return 0;
}
+int fflush_sync_and_check(FILE *f) {
+ int r;
+
+ assert(f);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
+ if (fsync(fileno(f)) < 0)
+ return -errno;
+
+ return 0;
+}
+
/* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern) {
_cleanup_umask_ mode_t u = 0;
@@ -1399,7 +1428,7 @@ int open_serialization_fd(const char *ident) {
if (fd < 0) {
const char *path;
- path = getpid() == 1 ? "/run/systemd" : "/tmp";
+ path = getpid_cached() == 1 ? "/run/systemd" : "/tmp";
fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return fd;
@@ -1497,3 +1526,77 @@ int mkdtemp_malloc(const char *template, char **ret) {
*ret = p;
return 0;
}
+
+static inline void funlockfilep(FILE **f) {
+ funlockfile(*f);
+}
+
+int read_line(FILE *f, size_t limit, char **ret) {
+ _cleanup_free_ char *buffer = NULL;
+ size_t n = 0, allocated = 0, count = 0;
+
+ assert(f);
+
+ /* Something like a bounded version of getline().
+ *
+ * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string
+ * returned.
+ *
+ * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from
+ * the number of characters in the returned string). When EOF is hit, 0 is returned.
+ *
+ * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding
+ * delimiters. If the limit is hit we fail and return -ENOBUFS.
+ *
+ * If a line shall be skipped ret may be initialized as NULL. */
+
+ if (ret) {
+ if (!GREEDY_REALLOC(buffer, allocated, 1))
+ return -ENOMEM;
+ }
+
+ {
+ _cleanup_(funlockfilep) FILE *flocked = f;
+ flockfile(f);
+
+ for (;;) {
+ int c;
+
+ if (n >= limit)
+ return -ENOBUFS;
+
+ errno = 0;
+ c = fgetc_unlocked(f);
+ if (c == EOF) {
+ /* if we read an error, and have no data to return, then propagate the error */
+ if (ferror_unlocked(f) && n == 0)
+ return errno > 0 ? -errno : -EIO;
+
+ break;
+ }
+
+ count++;
+
+ if (IN_SET(c, '\n', 0)) /* Reached a delimiter */
+ break;
+
+ if (ret) {
+ if (!GREEDY_REALLOC(buffer, allocated, n + 2))
+ return -ENOMEM;
+
+ buffer[n] = (char) c;
+ }
+
+ n++;
+ }
+ }
+
+ if (ret) {
+ buffer[n] = 0;
+
+ *ret = buffer;
+ buffer = NULL;
+ }
+
+ return (int) count;
+}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 6098562265..eba05be2a9 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -29,15 +29,16 @@
#include "time-util.h"
typedef enum {
- WRITE_STRING_FILE_CREATE = 1,
- WRITE_STRING_FILE_ATOMIC = 2,
- WRITE_STRING_FILE_AVOID_NEWLINE = 4,
- WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
+ WRITE_STRING_FILE_CREATE = 1<<0,
+ WRITE_STRING_FILE_ATOMIC = 1<<1,
+ WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2,
+ WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3,
+ WRITE_STRING_FILE_SYNC = 1<<4,
} WriteStringFileFlags;
-int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts);
-static inline int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
- return write_string_stream_ts(f, line, enforce_newline, NULL);
+int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
+static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
+ return write_string_stream_ts(f, line, flags, NULL);
}
int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags flags, struct timespec *ts);
static inline int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
@@ -77,6 +78,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
} else
int fflush_and_check(FILE *f);
+int fflush_sync_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern);
@@ -99,3 +101,5 @@ int link_tmpfile(int fd, const char *path, const char *target);
int read_nul_string(FILE *f, char **ret);
int mkdtemp_malloc(const char *template, char **ret);
+
+int read_line(FILE *f, size_t limit, char **ret);
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index 4abd1adef6..88d97d460a 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -23,8 +23,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
-#include <time.h>
#include <linux/magic.h>
+#include <time.h>
#include <unistd.h>
#include "alloc-util.h"
@@ -308,7 +308,7 @@ int fd_warn_permissions(const char *path, int fd) {
if (st.st_mode & 0002)
log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
- if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+ if (getpid_cached() == 1 && (st.st_mode & 0044) != 0044)
log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
return 0;
@@ -324,7 +324,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
mkdir_parents(path, 0755);
fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
- (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);
+ IN_SET(mode, 0, MODE_INVALID) ? 0644 : mode);
if (fd < 0)
return -errno;
@@ -359,22 +359,25 @@ int touch(const char *path) {
}
int symlink_idempotent(const char *from, const char *to) {
- _cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
if (symlink(from, to) < 0) {
+ _cleanup_free_ char *p = NULL;
+
if (errno != EEXIST)
return -errno;
r = readlink_malloc(to, &p);
- if (r < 0)
+ if (r == -EINVAL) /* Not a symlink? In that case return the original error we encountered: -EEXIST */
+ return -EEXIST;
+ if (r < 0) /* Any other error? In that case propagate it as is */
return r;
- if (!streq(p, from))
- return -EINVAL;
+ if (!streq(p, from)) /* Not the symlink we want it to be? In that case, propagate the original -EEXIST */
+ return -EEXIST;
}
return 0;
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 50fefb0b54..4bfaa864b4 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -34,7 +34,7 @@
#include "strv.h"
#include "util.h"
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
#include <pthread.h>
#include "list.h"
#endif
@@ -142,7 +142,7 @@ typedef uint8_t dib_raw_t;
#define DIB_FREE UINT_MAX
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
struct hashmap_debug_info {
LIST_FIELDS(struct hashmap_debug_info, debug_list);
unsigned max_entries; /* high watermark of n_entries */
@@ -499,7 +499,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
dibs = dib_raw_ptr(h);
assert(dibs[idx] != DIB_RAW_FREE);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.rem_count++;
h->debug.last_rem_idx = idx;
#endif
@@ -508,7 +508,7 @@ static void base_remove_entry(HashmapBase *h, unsigned idx) {
/* Find the stop bucket ("right"). It is either free or has DIB == 0. */
for (right = next_idx(h, left); ; right = next_idx(h, right)) {
raw_dib = dibs[right];
- if (raw_dib == 0 || raw_dib == DIB_RAW_FREE)
+ if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
break;
/* The buckets are not supposed to be all occupied and with DIB > 0.
@@ -578,7 +578,7 @@ static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *
assert(e->p.b.key == i->next_key);
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -635,7 +635,7 @@ static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
}
idx = i->idx;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
i->prev_idx = idx;
#endif
@@ -658,7 +658,7 @@ static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
return IDX_NIL;
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
if (i->idx == IDX_FIRST) {
i->put_count = h->debug.put_count;
i->rem_count = h->debug.rem_count;
@@ -750,7 +750,7 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu
shared_hash_key_initialized= true;
}
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.func = func;
h->debug.file = file;
h->debug.line = line;
@@ -807,7 +807,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
assert(!h->has_indirect);
assert(!h->n_direct_entries);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
@@ -919,7 +919,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
dib_raw_t raw_dib, *dibs;
unsigned dib, distance;
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.put_count++;
#endif
@@ -927,7 +927,7 @@ static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
for (distance = 0; ; distance++) {
raw_dib = dibs[idx];
- if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) {
+ if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
if (raw_dib == DIB_RAW_REHASH)
bucket_move_entry(h, swap, idx, IDX_TMP);
@@ -1012,7 +1012,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
n_entries_inc(h);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
#endif
@@ -1240,7 +1240,7 @@ int hashmap_replace(Hashmap *h, const void *key, void *value) {
idx = bucket_scan(h, hash, key);
if (idx != IDX_NIL) {
e = plain_bucket_at(h, idx);
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
/* Although the key is equal, the key pointer may have changed,
* and this would break our assumption for iterating. So count
* this operation as incompatible with iteration. */
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index 6d1ae48b21..c1089652d3 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -58,7 +58,7 @@ typedef struct Set Set; /* Stores just keys */
typedef struct {
unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */
unsigned prev_idx; /* idx in previous iteration */
@@ -89,7 +89,7 @@ typedef struct {
(Hashmap*)(h), \
(void)0)
-#ifdef ENABLE_DEBUG_HASHMAP
+#if ENABLE_DEBUG_HASHMAP
# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 2d6e377f0a..766770389c 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
char octchar(int x) {
@@ -569,7 +570,7 @@ static int base64_append_width(char **prefix, int plen,
lines = (len + width - 1) / width;
- slen = sep ? strlen(sep) : 0;
+ slen = strlen_ptr(sep);
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
if (!t)
return -ENOMEM;
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index a94037b303..ea9e77087f 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -90,9 +90,7 @@ static bool hostname_valid_char(char c) {
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
- c == '-' ||
- c == '_' ||
- c == '.';
+ IN_SET(c, '-', '_', '.');
}
/**
@@ -196,8 +194,11 @@ bool is_gateway_hostname(const char *hostname) {
* synthetic "gateway" host. */
return
- strcaseeq(hostname, "gateway") ||
- strcaseeq(hostname, "gateway.");
+ strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.")
+#if ENABLE_COMPAT_GATEWAY_HOSTNAME
+ || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.")
+#endif
+ ;
}
int sethostname_idempotent(const char *s) {
@@ -232,7 +233,7 @@ int read_hostname_config(const char *path, char **hostname) {
/* may have comments, ignore them */
FOREACH_LINE(l, f, return -errno) {
truncate_nl(l);
- if (l[0] != '\0' && l[0] != '#') {
+ if (!IN_SET(l[0], '\0', '#')) {
/* found line with value */
name = hostname_cleanup(l);
name = strdup(name);
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index d52fdad3ac..e27faba75f 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -308,22 +308,22 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
return 0;
}
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) {
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret) {
int r;
assert(s);
r = in_addr_from_string(AF_INET, s, ret);
if (r >= 0) {
- if (family)
- *family = AF_INET;
+ if (ret_family)
+ *ret_family = AF_INET;
return 0;
}
r = in_addr_from_string(AF_INET6, s, ret);
if (r >= 0) {
- if (family)
- *family = AF_INET6;
+ if (ret_family)
+ *ret_family = AF_INET6;
return 0;
}
@@ -371,13 +371,13 @@ int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_u
return r;
}
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
return 32 - u32ctz(be32toh(addr->s_addr));
}
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) {
assert(addr);
assert(prefixlen <= 32);
@@ -390,7 +390,7 @@ struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char
return addr;
}
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
uint8_t msb_octet = *(uint8_t*) addr;
/* addr may not be aligned, so make sure we only access it byte-wise */
@@ -414,18 +414,18 @@ int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixl
return 0;
}
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) {
unsigned char prefixlen;
int r;
assert(addr);
assert(mask);
- r = in_addr_default_prefixlen(addr, &prefixlen);
+ r = in4_addr_default_prefixlen(addr, &prefixlen);
if (r < 0)
return r;
- in_addr_prefixlen_to_netmask(mask, prefixlen);
+ in4_addr_prefixlen_to_netmask(mask, prefixlen);
return 0;
}
@@ -435,7 +435,7 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
if (family == AF_INET) {
struct in_addr mask;
- if (!in_addr_prefixlen_to_netmask(&mask, prefixlen))
+ if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
return -EINVAL;
addr->in.s_addr &= mask.s_addr;
@@ -465,10 +465,57 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
return -EAFNOSUPPORT;
}
-int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen) {
+int in_addr_prefix_covers(int family,
+ const union in_addr_union *prefix,
+ unsigned char prefixlen,
+ const union in_addr_union *address) {
+
+ union in_addr_union masked_prefix, masked_address;
+ int r;
+
+ assert(prefix);
+ assert(address);
+
+ masked_prefix = *prefix;
+ r = in_addr_mask(family, &masked_prefix, prefixlen);
+ if (r < 0)
+ return r;
+
+ masked_address = *address;
+ r = in_addr_mask(family, &masked_address, prefixlen);
+ if (r < 0)
+ return r;
+
+ return in_addr_equal(family, &masked_prefix, &masked_address);
+}
+
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
+ uint8_t u;
+ int r;
+
+ if (!IN_SET(family, AF_INET, AF_INET6))
+ return -EAFNOSUPPORT;
+
+ r = safe_atou8(p, &u);
+ if (r < 0)
+ return r;
+
+ if (u > FAMILY_ADDRESS_SIZE(family) * 8)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
+int in_addr_prefix_from_string(
+ const char *p,
+ int family,
+ union in_addr_union *ret_prefix,
+ unsigned char *ret_prefixlen) {
+
union in_addr_union buffer;
const char *e, *l;
- uint8_t k;
+ unsigned char k;
int r;
assert(p);
@@ -486,23 +533,58 @@ int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *r
if (r < 0)
return r;
- k = FAMILY_ADDRESS_SIZE(family) * 8;
-
if (e) {
- uint8_t n;
-
- r = safe_atou8(e + 1, &n);
+ r = in_addr_parse_prefixlen(family, e+1, &k);
if (r < 0)
return r;
+ } else
+ k = FAMILY_ADDRESS_SIZE(family) * 8;
- if (n > k)
- return -ERANGE;
+ if (ret_prefix)
+ *ret_prefix = buffer;
+ if (ret_prefixlen)
+ *ret_prefixlen = k;
- k = n;
- }
+ return 0;
+}
+
+int in_addr_prefix_from_string_auto(
+ const char *p,
+ int *ret_family,
+ union in_addr_union *ret_prefix,
+ unsigned char *ret_prefixlen) {
+
+ union in_addr_union buffer;
+ const char *e, *l;
+ unsigned char k;
+ int family, r;
+
+ assert(p);
+
+ e = strchr(p, '/');
+ if (e)
+ l = strndupa(p, e - p);
+ else
+ l = p;
- *ret_prefix = buffer;
- *ret_prefixlen = k;
+ r = in_addr_from_string_auto(l, &family, &buffer);
+ if (r < 0)
+ return r;
+
+ if (e) {
+ r = in_addr_parse_prefixlen(family, e+1, &k);
+ if (r < 0)
+ return r;
+ } else
+ k = FAMILY_ADDRESS_SIZE(family) * 8;
+
+ if (ret_family)
+ *ret_family = family;
+ if (ret_prefix)
+ *ret_prefix = buffer;
+ if (ret_prefixlen)
+ *ret_prefixlen = k;
return 0;
+
}
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index 14e27246b5..59f8eb7edf 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -53,17 +53,20 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
-int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
+int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
-unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
-struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
-int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
-int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
+struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
+int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
+int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
-int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, uint8_t *ret_prefixlen);
+int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
+int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
+int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
+int in_addr_prefix_from_string_auto(const char *p, int *ret_family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
static inline size_t FAMILY_ADDRESS_SIZE(int family) {
- assert(family == AF_INET || family == AF_INET6);
+ assert(IN_SET(family, AF_INET, AF_INET6));
return family == AF_INET6 ? 16 : 4;
}
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
index 4684ed3bfc..d9b69adde9 100644
--- a/src/basic/io-util.h
+++ b/src/basic/io-util.h
@@ -40,14 +40,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-#define IOVEC_SET_STRING(i, s) \
- do { \
- struct iovec *_i = &(i); \
- char *_s = (char *)(s); \
- _i->iov_base = _s; \
- _i->iov_len = strlen(_s); \
- } while (false)
-
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
size_t r = 0;
@@ -93,3 +85,8 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
return FILE_SIZE_VALID(l);
}
+
+#define IOVEC_INIT(base, len) { .iov_base = (base), .iov_len = (len) }
+#define IOVEC_MAKE(base, len) (struct iovec) IOVEC_INIT(base, len)
+#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
+#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
diff --git a/src/basic/journal-importer.c b/src/basic/journal-importer.c
index 7d72effdea..e750101165 100644
--- a/src/basic/journal-importer.c
+++ b/src/basic/journal-importer.c
@@ -20,8 +20,9 @@
#include <unistd.h>
#include "alloc-util.h"
-#include "journal-importer.h"
#include "fd-util.h"
+#include "io-util.h"
+#include "journal-importer.h"
#include "parse-util.h"
#include "string-util.h"
#include "unaligned.h"
@@ -38,7 +39,7 @@ static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1))
return log_oom();
- iovw->iovec[iovw->count++] = (struct iovec) {data, len};
+ iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
return 0;
}
@@ -153,9 +154,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) {
static int fill_fixed_size(JournalImporter *imp, void **data, size_t size) {
assert(imp);
- assert(imp->state == IMPORTER_STATE_DATA_START ||
- imp->state == IMPORTER_STATE_DATA ||
- imp->state == IMPORTER_STATE_DATA_FINISH);
+ assert(IN_SET(imp->state, IMPORTER_STATE_DATA_START, IMPORTER_STATE_DATA, IMPORTER_STATE_DATA_FINISH));
assert(size <= DATA_SIZE_MAX);
assert(imp->offset <= imp->filled);
assert(imp->filled <= imp->size);
diff --git a/src/basic/log.c b/src/basic/log.c
index 3fd53800a0..4f0fe54579 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -74,6 +74,7 @@ static bool show_location = false;
static bool upgrade_syslog_to_journal = false;
static bool always_reopen_console = false;
+static bool open_when_needed = false;
/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
@@ -84,7 +85,7 @@ void log_close_console(void) {
if (console_fd < 0)
return;
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
if (console_fd >= 3)
safe_close(console_fd);
@@ -140,7 +141,7 @@ static int create_log_socket(int type) {
/* We need a blocking fd here since we'd otherwise lose
messages way too early. However, let's not hang forever in the
unlikely case of a deadlock. */
- if (getpid() == 1)
+ if (getpid_cached() == 1)
timeval_store(&tv, 10 * USEC_PER_MSEC);
else
timeval_store(&tv, 10 * USEC_PER_SEC);
@@ -248,7 +249,7 @@ int log_open(void) {
}
if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) ||
- getpid() == 1 ||
+ getpid_cached() == 1 ||
isatty(STDERR_FILENO) <= 0) {
if (IN_SET(log_target, LOG_TARGET_AUTO,
@@ -351,26 +352,26 @@ static int write_to_console(
if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
xsprintf(prefix, "<%i>", level);
- IOVEC_SET_STRING(iovec[n++], prefix);
+ iovec[n++] = IOVEC_MAKE_STRING(prefix);
}
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
if (show_location) {
snprintf(location, sizeof(location), "(%s:%i) ", file, line);
- IOVEC_SET_STRING(iovec[n++], location);
+ iovec[n++] = IOVEC_MAKE_STRING(location);
}
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED);
- IOVEC_SET_STRING(iovec[n++], buffer);
+ iovec[n++] = IOVEC_MAKE_STRING(ANSI_HIGHLIGHT_RED);
+ iovec[n++] = IOVEC_MAKE_STRING(buffer);
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL);
- IOVEC_SET_STRING(iovec[n++], "\n");
+ iovec[n++] = IOVEC_MAKE_STRING(ANSI_NORMAL);
+ iovec[n++] = IOVEC_MAKE_STRING("\n");
if (writev(console_fd, iovec, n) < 0) {
- if (errno == EIO && getpid() == 1) {
+ if (errno == EIO && getpid_cached() == 1) {
/* If somebody tried to kick us from our
* console tty (via vhangup() or suchlike),
@@ -423,13 +424,13 @@ static int write_to_syslog(
if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
return -EINVAL;
- xsprintf(header_pid, "["PID_FMT"]: ", getpid());
+ xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
- IOVEC_SET_STRING(iovec[0], header_priority);
- IOVEC_SET_STRING(iovec[1], header_time);
- IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
- IOVEC_SET_STRING(iovec[3], header_pid);
- IOVEC_SET_STRING(iovec[4], buffer);
+ iovec[0] = IOVEC_MAKE_STRING(header_priority);
+ iovec[1] = IOVEC_MAKE_STRING(header_time);
+ iovec[2] = IOVEC_MAKE_STRING(program_invocation_short_name);
+ iovec[3] = IOVEC_MAKE_STRING(header_pid);
+ iovec[4] = IOVEC_MAKE_STRING(buffer);
/* When using syslog via SOCK_STREAM separate the messages by NUL chars */
if (syslog_is_stream)
@@ -468,13 +469,13 @@ static int write_to_kmsg(
return 0;
xsprintf(header_priority, "<%i>", level);
- xsprintf(header_pid, "["PID_FMT"]: ", getpid());
+ xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
- IOVEC_SET_STRING(iovec[0], header_priority);
- IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
- IOVEC_SET_STRING(iovec[2], header_pid);
- IOVEC_SET_STRING(iovec[3], buffer);
- IOVEC_SET_STRING(iovec[4], "\n");
+ iovec[0] = IOVEC_MAKE_STRING(header_priority);
+ iovec[1] = IOVEC_MAKE_STRING(program_invocation_short_name);
+ iovec[2] = IOVEC_MAKE_STRING(header_pid);
+ iovec[3] = IOVEC_MAKE_STRING(buffer);
+ iovec[4] = IOVEC_MAKE_STRING("\n");
if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
return -errno;
@@ -547,10 +548,10 @@ static int write_to_journal(
log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
- IOVEC_SET_STRING(iovec[0], header);
- IOVEC_SET_STRING(iovec[1], "MESSAGE=");
- IOVEC_SET_STRING(iovec[2], buffer);
- IOVEC_SET_STRING(iovec[3], "\n");
+ iovec[0] = IOVEC_MAKE_STRING(header);
+ iovec[1] = IOVEC_MAKE_STRING("MESSAGE=");
+ iovec[2] = IOVEC_MAKE_STRING(buffer);
+ iovec[3] = IOVEC_MAKE_STRING("\n");
mh.msg_iov = iovec;
mh.msg_iovlen = ELEMENTSOF(iovec);
@@ -585,6 +586,9 @@ int log_dispatch_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
+ if (open_when_needed)
+ log_open();
+
do {
char *e;
int k = 0;
@@ -640,6 +644,9 @@ int log_dispatch_internal(
buffer = e;
} while (buffer);
+ if (open_when_needed)
+ log_close();
+
return -error;
}
@@ -804,6 +811,7 @@ noreturn void log_assert_failed_realm(
const char *file,
int line,
const char *func) {
+ log_open();
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Assertion '%s' failed at %s:%u, function %s(). Aborting.");
abort();
@@ -815,6 +823,7 @@ noreturn void log_assert_failed_unreachable_realm(
const char *file,
int line,
const char *func) {
+ log_open();
log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func,
"Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
abort();
@@ -832,9 +841,8 @@ void log_assert_failed_return_realm(
}
int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) {
- log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
- ENOMEM, file, line, func, "Out of memory.");
- return -ENOMEM;
+ return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR),
+ ENOMEM, file, line, func, "Out of memory.");
}
int log_format_iovec(
@@ -870,7 +878,7 @@ int log_format_iovec(
* the next format string */
VA_FORMAT_ADVANCE(format, ap);
- IOVEC_SET_STRING(iovec[(*n)++], m);
+ iovec[(*n)++] = IOVEC_MAKE_STRING(m);
if (newline_separator) {
iovec[*n].iov_base = (char*) &nl;
@@ -891,9 +899,9 @@ int log_struct_internal(
const char *func,
const char *format, ...) {
+ LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
char buf[LINE_MAX];
bool found = false;
- LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
PROTECT_ERRNO;
va_list ap;
@@ -909,38 +917,48 @@ int log_struct_internal(
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
- if (IN_SET(log_target, LOG_TARGET_AUTO,
- LOG_TARGET_JOURNAL_OR_KMSG,
- LOG_TARGET_JOURNAL) &&
- journal_fd >= 0) {
- char header[LINE_MAX];
- struct iovec iovec[17] = {};
- unsigned n = 0, i;
- int r;
- struct msghdr mh = {
- .msg_iov = iovec,
- };
- bool fallback = false;
-
- /* If the journal is available do structured logging */
- log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
- IOVEC_SET_STRING(iovec[n++], header);
+ if (IN_SET(log_target,
+ LOG_TARGET_AUTO,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_JOURNAL)) {
+
+ if (open_when_needed)
+ log_open_journal();
+
+ if (journal_fd >= 0) {
+ char header[LINE_MAX];
+ struct iovec iovec[17] = {};
+ unsigned n = 0, i;
+ int r;
+ struct msghdr mh = {
+ .msg_iov = iovec,
+ };
+ bool fallback = false;
+
+ /* If the journal is available do structured logging */
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
+ iovec[n++] = IOVEC_MAKE_STRING(header);
+
+ va_start(ap, format);
+ r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
+ if (r < 0)
+ fallback = true;
+ else {
+ mh.msg_iovlen = n;
+ (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
+ }
- va_start(ap, format);
- r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
- if (r < 0)
- fallback = true;
- else {
- mh.msg_iovlen = n;
- (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
- }
+ va_end(ap);
+ for (i = 1; i < n; i += 2)
+ free(iovec[i].iov_base);
- va_end(ap);
- for (i = 1; i < n; i += 2)
- free(iovec[i].iov_base);
+ if (!fallback) {
+ if (open_when_needed)
+ log_close();
- if (!fallback)
- return -error;
+ return -error;
+ }
+ }
}
/* Fallback if journal logging is not available or didn't work. */
@@ -967,12 +985,83 @@ int log_struct_internal(
}
va_end(ap);
- if (!found)
+ if (!found) {
+ if (open_when_needed)
+ log_close();
+
return -error;
+ }
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
}
+int log_struct_iovec_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const struct iovec input_iovec[],
+ size_t n_input_iovec) {
+
+ LogRealm realm = LOG_REALM_REMOVE_LEVEL(level);
+ PROTECT_ERRNO;
+ size_t i;
+ char *m;
+
+ if (error < 0)
+ error = -error;
+
+ if (_likely_(LOG_PRI(level) > log_max_level[realm]))
+ return -error;
+
+ if (log_target == LOG_TARGET_NULL)
+ return -error;
+
+ if ((level & LOG_FACMASK) == 0)
+ level = log_facility | LOG_PRI(level);
+
+ if (IN_SET(log_target, LOG_TARGET_AUTO,
+ LOG_TARGET_JOURNAL_OR_KMSG,
+ LOG_TARGET_JOURNAL) &&
+ journal_fd >= 0) {
+
+ struct iovec iovec[1 + n_input_iovec*2];
+ char header[LINE_MAX];
+ struct msghdr mh = {
+ .msg_iov = iovec,
+ .msg_iovlen = 1 + n_input_iovec*2,
+ };
+
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
+ iovec[0] = IOVEC_MAKE_STRING(header);
+
+ for (i = 0; i < n_input_iovec; i++) {
+ iovec[1+i*2] = input_iovec[i];
+ iovec[1+i*2+1] = IOVEC_MAKE_STRING("\n");
+ }
+
+ if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) >= 0)
+ return -error;
+ }
+
+ for (i = 0; i < n_input_iovec; i++) {
+ if (input_iovec[i].iov_len < strlen("MESSAGE="))
+ continue;
+
+ if (memcmp(input_iovec[i].iov_base, "MESSAGE=", strlen("MESSAGE=")) == 0)
+ break;
+ }
+
+ if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
+ return -error;
+
+ m = strndupa(input_iovec[i].iov_base + strlen("MESSAGE="),
+ input_iovec[i].iov_len - strlen("MESSAGE="));
+
+ return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
+}
+
int log_set_target_from_string(const char *e) {
LogTarget t;
@@ -1152,10 +1241,6 @@ void log_received_signal(int level, const struct signalfd_siginfo *si) {
}
-void log_set_upgrade_syslog_to_journal(bool b) {
- upgrade_syslog_to_journal = b;
-}
-
int log_syntax_internal(
const char *unit,
int level,
@@ -1189,7 +1274,7 @@ int log_syntax_internal(
va_end(ap);
if (unit)
- unit_fmt = getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
+ unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
return log_struct_internal(
LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
@@ -1203,6 +1288,14 @@ int log_syntax_internal(
NULL);
}
+void log_set_upgrade_syslog_to_journal(bool b) {
+ upgrade_syslog_to_journal = b;
+}
+
void log_set_always_reopen_console(bool b) {
always_reopen_console = b;
}
+
+void log_set_open_when_needed(bool b) {
+ open_when_needed = b;
+}
diff --git a/src/basic/log.h b/src/basic/log.h
index ff5d776b1d..10a6032788 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -30,6 +30,7 @@
#include "sd-id128.h"
#include "macro.h"
+#include "process-util.h"
typedef enum LogRealm {
LOG_REALM_SYSTEMD,
@@ -186,6 +187,15 @@ int log_format_iovec(
const char *format,
va_list ap) _printf_(6, 0);
+int log_struct_iovec_internal(
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const struct iovec input_iovec[],
+ size_t n_input_iovec);
+
/* This modifies the buffer passed! */
int log_dump_internal(
int level,
@@ -247,7 +257,7 @@ void log_assert_failed_return_realm(
#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
-#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
/* Logging triggered by an errno-like error */
#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
@@ -255,7 +265,7 @@ void log_assert_failed_return_realm(
#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
-#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid_cached() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
#ifdef LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
@@ -269,6 +279,11 @@ void log_assert_failed_return_realm(
error, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__)
+#define log_struct_iovec_errno(level, error, iovec, n_iovec) \
+ log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
+ error, __FILE__, __LINE__, __func__, iovec, n_iovec)
+#define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec)
+
/* This modifies the buffer passed! */
#define log_dump(level, buffer) \
log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \
@@ -288,6 +303,7 @@ void log_received_signal(int level, const struct signalfd_siginfo *si);
void log_set_upgrade_syslog_to_journal(bool b);
void log_set_always_reopen_console(bool b);
+void log_set_open_when_needed(bool b);
int log_syntax_internal(
const char *unit,
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index 8c8cc78ebf..8f4f0e3a24 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -21,7 +21,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
-#ifdef HAVE_LINUX_MEMFD_H
+#if HAVE_LINUX_MEMFD_H
#include <linux/memfd.h>
#endif
#include <stdio.h>
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 065f0ac4af..1ddefb7fbb 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -1,4 +1,6 @@
basic_sources_plain = files('''
+ MurmurHash2.c
+ MurmurHash2.h
af-list.c
af-list.h
alloc-util.c
@@ -16,6 +18,8 @@ basic_sources_plain = files('''
bitmap.c
bitmap.h
blkid-util.h
+ bpf-program.c
+ bpf-program.h
btrfs-ctree.h
btrfs-util.c
btrfs-util.h
@@ -24,10 +28,10 @@ basic_sources_plain = files('''
bus-label.h
calendarspec.c
calendarspec.h
- capability-util.c
- capability-util.h
cap-list.c
cap-list.h
+ capability-util.c
+ capability-util.h
cgroup-util.c
cgroup-util.h
chattr-util.c
@@ -61,10 +65,10 @@ basic_sources_plain = files('''
extract-word.h
fd-util.c
fd-util.h
- fileio.c
- fileio.h
fileio-label.c
fileio-label.h
+ fileio.c
+ fileio.h
format-util.h
fs-util.c
fs-util.h
@@ -82,9 +86,9 @@ basic_sources_plain = files('''
hostname-util.h
in-addr-util.c
in-addr-util.h
- ioprio.h
io-util.c
io-util.h
+ ioprio.h
journal-importer.c
journal-importer.h
khash.c
@@ -106,13 +110,11 @@ basic_sources_plain = files('''
mempool.c
mempool.h
missing_syscall.h
+ mkdir-label.c
mkdir.c
mkdir.h
- mkdir-label.c
mount-util.c
mount-util.h
- MurmurHash2.c
- MurmurHash2.h
nss-util.h
ordered-set.c
ordered-set.h
@@ -138,9 +140,12 @@ basic_sources_plain = files('''
rlimit-util.h
rm-rf.c
rm-rf.h
+ securebits-util.c
+ securebits-util.h
securebits.h
selinux-util.c
selinux-util.h
+ set.c
set.h
sigbus.c
sigbus.h
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 7830a4f415..352d2b024b 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -40,7 +40,7 @@
#include <uchar.h>
#include <unistd.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#endif
@@ -48,11 +48,11 @@
#include <asm/sgidefs.h>
#endif
-#ifdef HAVE_LINUX_BTRFS_H
+#if HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
-#ifdef HAVE_LINUX_VM_SOCKETS_H
+#if HAVE_LINUX_VM_SOCKETS_H
#include <linux/vm_sockets.h>
#else
#define VMADDR_CID_ANY -1U
@@ -204,7 +204,7 @@ struct sockaddr_vm {
#define BTRFS_QGROUP_LEVEL_SHIFT 48
#endif
-#ifndef HAVE_LINUX_BTRFS_H
+#if ! HAVE_LINUX_BTRFS_H
struct btrfs_ioctl_vol_args {
int64_t fd;
char name[BTRFS_PATH_NAME_MAX + 1];
@@ -546,8 +546,8 @@ struct btrfs_ioctl_quota_ctl_args {
#define MAX_HANDLE_SZ 128
#endif
-#ifndef HAVE_SECURE_GETENV
-# ifdef HAVE___SECURE_GETENV
+#if ! HAVE_SECURE_GETENV
+# if HAVE___SECURE_GETENV
# define secure_getenv __secure_getenv
# else
# error "neither secure_getenv nor __secure_getenv are available"
@@ -606,15 +606,14 @@ struct input_mask {
#else
#define __O_TMPFILE 020000000
#endif
+#endif
/* a horrid kludge trying to make sure that this will fail on old kernels */
#ifndef O_TMPFILE
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#endif
-#endif
-
-#if !HAVE_DECL_LO_FLAGS_PARTSCAN
+#if !HAVE_LO_FLAGS_PARTSCAN
#define LO_FLAGS_PARTSCAN 8
#endif
@@ -626,7 +625,7 @@ struct input_mask {
#define LOOP_CTL_GET_FREE 0x4C82
#endif
-#if !HAVE_DECL_IFLA_INET6_ADDR_GEN_MODE
+#if !HAVE_IFLA_INET6_ADDR_GEN_MODE
#define IFLA_INET6_UNSPEC 0
#define IFLA_INET6_FLAGS 1
#define IFLA_INET6_CONF 2
@@ -644,11 +643,11 @@ struct input_mask {
#define IN6_ADDR_GEN_MODE_NONE 1
#endif
-#if !HAVE_DECL_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
+#if !HAVE_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2
#endif
-#if !HAVE_DECL_IFLA_MACVLAN_FLAGS
+#if !HAVE_IFLA_MACVLAN_FLAGS
#define IFLA_MACVLAN_UNSPEC 0
#define IFLA_MACVLAN_MODE 1
#define IFLA_MACVLAN_FLAGS 2
@@ -657,7 +656,7 @@ struct input_mask {
#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPVLAN_MODE
+#if !HAVE_IFLA_IPVLAN_MODE
#define IFLA_IPVLAN_UNSPEC 0
#define IFLA_IPVLAN_MODE 1
#define __IFLA_IPVLAN_MAX 2
@@ -669,7 +668,7 @@ struct input_mask {
#define IPVLAN_MAX 2
#endif
-#if !HAVE_DECL_IFLA_VTI_REMOTE
+#if !HAVE_IFLA_VTI_REMOTE
#define IFLA_VTI_UNSPEC 0
#define IFLA_VTI_LINK 1
#define IFLA_VTI_IKEY 2
@@ -681,7 +680,7 @@ struct input_mask {
#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_PHYS_PORT_ID
+#if !HAVE_IFLA_PHYS_PORT_ID
#define IFLA_EXT_MASK 29
#undef IFLA_PROMISCUITY
#define IFLA_PROMISCUITY 30
@@ -694,7 +693,7 @@ struct input_mask {
#define IFLA_MAX (__IFLA_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BOND_AD_INFO
+#if !HAVE_IFLA_BOND_AD_INFO
#define IFLA_BOND_UNSPEC 0
#define IFLA_BOND_MODE 1
#define IFLA_BOND_ACTIVE_SLAVE 2
@@ -724,7 +723,7 @@ struct input_mask {
#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_VLAN_PROTOCOL
+#if !HAVE_IFLA_VLAN_PROTOCOL
#define IFLA_VLAN_UNSPEC 0
#define IFLA_VLAN_ID 1
#define IFLA_VLAN_FLAGS 2
@@ -736,7 +735,7 @@ struct input_mask {
#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_VXLAN_GPE
+#if !HAVE_IFLA_VXLAN_GPE
#define IFLA_VXLAN_UNSPEC 0
#define IFLA_VXLAN_ID 1
#define IFLA_VXLAN_GROUP 2
@@ -771,7 +770,7 @@ struct input_mask {
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_GENEVE_LABEL
+#if !HAVE_IFLA_GENEVE_LABEL
#define IFLA_GENEVE_UNSPEC 0
#define IFLA_GENEVE_ID 1
#define IFLA_GENEVE_REMOTE 2
@@ -790,7 +789,7 @@ struct input_mask {
#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT
+#if !HAVE_IFLA_IPTUN_ENCAP_DPORT
#define IFLA_IPTUN_UNSPEC 0
#define IFLA_IPTUN_LINK 1
#define IFLA_IPTUN_LOCAL 2
@@ -816,7 +815,7 @@ struct input_mask {
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_GRE_ENCAP_DPORT
+#if !HAVE_IFLA_GRE_ENCAP_DPORT
#define IFLA_GRE_UNSPEC 0
#define IFLA_GRE_LINK 1
#define IFLA_GRE_IFLAGS 2
@@ -841,7 +840,7 @@ struct input_mask {
#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRIDGE_VLAN_INFO
+#if !HAVE_IFLA_BRIDGE_VLAN_INFO
#define IFLA_BRIDGE_FLAGS 0
#define IFLA_BRIDGE_MODE 1
#define IFLA_BRIDGE_VLAN_INFO 2
@@ -858,7 +857,7 @@ struct input_mask {
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
#endif
-#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
+#if !HAVE_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
#define IFLA_BR_HELLO_TIME 2
@@ -904,7 +903,7 @@ struct input_mask {
#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
+#if !HAVE_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
#define IFLA_BRPORT_PRIORITY 2
@@ -921,15 +920,42 @@ struct input_mask {
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BRPORT_PROXYARP
+#if !HAVE_FRA_UID_RANGE
+#define FRA_UNSPEC 0
+#define FRA_DST 1
+#define FRA_SRC 2
+#define FRA_IIFNAME 3
+#define FRA_GOTO 4
+#define FRA_UNUSED2 5
+#define FRA_PRIORITY 6
+#define FRA_UNUSED3 7
+#define FRA_UNUSED4 8
+#define FRA_UNUSED5 9
+#define FRA_FWMARK 10
+#define FRA_FLOW 11
+#define FRA_TUN_ID 12
+#define FRA_SUPPRESS_IFGROUP 13
+#define FRA_SUPPRESS_PREFIXLEN 14
+#define FRA_TABLE 15
+#define FRA_FWMASK 16
+#define FRA_OIFNAME 17
+#define FRA_PAD 18
+#define FRA_L3MDEV 19
+#define FRA_UID_RANGE 20
+#define __FRA_MAX 12
+
+#define FRA_MAX (__FRA_MAX - 1)
+#endif
+
+#if !HAVE_IFLA_BRPORT_PROXYARP
#define IFLA_BRPORT_PROXYARP 10
#endif
-#if !HAVE_DECL_IFLA_VRF_TABLE
+#if !HAVE_IFLA_VRF_TABLE
#define IFLA_VRF_TABLE 1
#endif
-#if !HAVE_DECL_NDA_IFINDEX
+#if !HAVE_NDA_IFINDEX
#define NDA_UNSPEC 0
#define NDA_DST 1
#define NDA_LLADDR 2
@@ -1013,7 +1039,7 @@ struct input_mask {
#define LOOPBACK_IFINDEX 1
#endif
-#if !HAVE_DECL_IFA_FLAGS
+#if !HAVE_IFA_FLAGS
#define IFA_FLAGS 8
#endif
@@ -1082,7 +1108,7 @@ struct input_mask {
#define KEY_ALS_TOGGLE 0x230
#endif
-#ifndef HAVE_KEY_SERIAL_T
+#if ! HAVE_KEY_SERIAL_T
typedef int32_t key_serial_t;
#endif
@@ -1102,6 +1128,10 @@ typedef int32_t key_serial_t;
#define KEYCTL_DESCRIBE 6
#endif
+#ifndef KEYCTL_LINK
+#define KEYCTL_LINK 8
+#endif
+
#ifndef KEYCTL_READ
#define KEYCTL_READ 11
#endif
@@ -1174,11 +1204,11 @@ typedef int32_t key_serial_t;
#ifndef IF_OPER_UP
#define IF_OPER_UP 6
-#ifndef HAVE_CHAR32_T
+#if ! HAVE_CHAR32_T
#define char32_t uint32_t
#endif
-#ifndef HAVE_CHAR16_T
+#if ! HAVE_CHAR16_T
#define char16_t uint16_t
#endif
@@ -1190,7 +1220,7 @@ typedef int32_t key_serial_t;
#define IFA_F_MCAUTOJOIN 0x400
#endif
-#ifndef HAVE_STRUCT_ETHTOOL_LINK_SETTINGS
+#if ! HAVE_STRUCT_ETHTOOL_LINK_SETTINGS
#define ETHTOOL_GLINKSETTINGS 0x0000004c /* Get ethtool_link_settings */
#define ETHTOOL_SLINKSETTINGS 0x0000004d /* Set ethtool_link_settings */
@@ -1217,6 +1247,15 @@ struct ethtool_link_settings {
#endif
+#if ! HAVE_STRUCT_FIB_RULE_UID_RANGE
+
+struct fib_rule_uid_range {
+ __u32 start;
+ __u32 end;
+};
+
+#endif
+
#endif
#ifndef SOL_ALG
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index e2860fc26a..9b84d46950 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -22,7 +22,9 @@
/* Missing glibc definitions to access certain kernel APIs */
-#if !HAVE_DECL_PIVOT_ROOT
+#include <sys/types.h>
+
+#if !HAVE_PIVOT_ROOT
static inline int missing_pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
}
@@ -32,7 +34,7 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old)
/* ======================================================================= */
-#if !HAVE_DECL_MEMFD_CREATE
+#if !HAVE_MEMFD_CREATE
# ifndef __NR_memfd_create
# if defined __x86_64__
# define __NR_memfd_create 319
@@ -75,7 +77,7 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
/* ======================================================================= */
-#if !HAVE_DECL_GETRANDOM
+#if !HAVE_GETRANDOM
# ifndef __NR_getrandom
# if defined __x86_64__
# define __NR_getrandom 318
@@ -124,7 +126,7 @@ static inline int missing_getrandom(void *buffer, size_t count, unsigned flags)
/* ======================================================================= */
-#if !HAVE_DECL_GETTID
+#if !HAVE_GETTID
static inline pid_t missing_gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
@@ -134,7 +136,7 @@ static inline pid_t missing_gettid(void) {
/* ======================================================================= */
-#if !HAVE_DECL_NAME_TO_HANDLE_AT
+#if !HAVE_NAME_TO_HANDLE_AT
# ifndef __NR_name_to_handle_at
# if defined(__x86_64__)
# define __NR_name_to_handle_at 303
@@ -171,7 +173,7 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil
/* ======================================================================= */
-#if !HAVE_DECL_SETNS
+#if !HAVE_SETNS
# ifndef __NR_setns
# if defined(__x86_64__)
# define __NR_setns 308
@@ -208,7 +210,7 @@ static inline pid_t raw_getpid(void) {
/* ======================================================================= */
-#if !HAVE_DECL_RENAMEAT2
+#if !HAVE_RENAMEAT2
# ifndef __NR_renameat2
# if defined __x86_64__
# define __NR_renameat2 316
@@ -253,7 +255,7 @@ static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, c
/* ======================================================================= */
-#if !HAVE_DECL_KCMP
+#if !HAVE_KCMP
static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
# ifdef __NR_kcmp
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
@@ -269,7 +271,7 @@ static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long i
/* ======================================================================= */
-#if !HAVE_DECL_KEYCTL
+#if !HAVE_KEYCTL
static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
# ifdef __NR_keyctl
return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
@@ -306,7 +308,7 @@ static inline key_serial_t missing_request_key(const char *type, const char *des
/* ======================================================================= */
-#if !HAVE_DECL_COPY_FILE_RANGE
+#if !HAVE_COPY_FILE_RANGE
# ifndef __NR_copy_file_range
# if defined(__x86_64__)
# define __NR_copy_file_range 326
@@ -341,3 +343,33 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in,
# define copy_file_range missing_copy_file_range
#endif
+
+#if !HAVE_BPF
+# ifndef __NR_bpf
+# if defined __i386__
+# define __NR_bpf 357
+# elif defined __x86_64__
+# define __NR_bpf 321
+# elif defined __aarch64__
+# define __NR_bpf 280
+# elif defined __sparc__
+# define __NR_bpf 349
+# elif defined __s390__
+# define __NR_bpf 351
+# else
+# warning "__NR_bpf not defined for your architecture"
+# endif
+# endif
+
+union bpf_attr;
+
+static inline int bpf(int cmd, union bpf_attr *attr, size_t size) {
+#ifdef __NR_bpf
+ return (int) syscall(__NR_bpf, cmd, attr, size);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#endif
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 6b1a98402c..7db09fc6a1 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -31,10 +31,13 @@
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
struct stat st;
+ int r;
- if (_mkdir(path, mode) >= 0)
- if (chmod_and_chown(path, mode, uid, gid) < 0)
- return -errno;
+ if (_mkdir(path, mode) >= 0) {
+ r = chmod_and_chown(path, mode, uid, gid);
+ if (r < 0)
+ return r;
+ }
if (lstat(path, &st) < 0)
return -errno;
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index 7b9400b47c..c4d451db73 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -472,14 +472,14 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
while ((x = set_steal_first(todo))) {
r = set_consume(done, x);
- if (r == -EEXIST || r == 0)
+ if (IN_SET(r, 0, -EEXIST))
continue;
if (r < 0)
return r;
/* Deal with mount points that are obstructed by a later mount */
r = path_is_mount_point(x, NULL, 0);
- if (r == -ENOENT || r == 0)
+ if (IN_SET(r, 0, -ENOENT))
continue;
if (r < 0)
return r;
@@ -526,30 +526,67 @@ int mount_move_root(const char *path) {
}
bool fstype_is_network(const char *fstype) {
- static const char table[] =
- "afs\0"
- "cifs\0"
- "smbfs\0"
- "sshfs\0"
- "ncpfs\0"
- "ncp\0"
- "nfs\0"
- "nfs4\0"
- "gfs\0"
- "gfs2\0"
- "glusterfs\0"
- "pvfs2\0" /* OrangeFS */
- "ocfs2\0"
- "lustre\0"
- ;
-
const char *x;
x = startswith(fstype, "fuse.");
if (x)
fstype = x;
- return nulstr_contains(table, fstype);
+ return STR_IN_SET(fstype,
+ "afs",
+ "cifs",
+ "smbfs",
+ "sshfs",
+ "ncpfs",
+ "ncp",
+ "nfs",
+ "nfs4",
+ "gfs",
+ "gfs2",
+ "glusterfs",
+ "pvfs2", /* OrangeFS */
+ "ocfs2",
+ "lustre");
+}
+
+bool fstype_is_api_vfs(const char *fstype) {
+ return STR_IN_SET(fstype,
+ "autofs",
+ "bpf",
+ "cgroup",
+ "cgroup2",
+ "configfs",
+ "cpuset",
+ "debugfs",
+ "devpts",
+ "devtmpfs",
+ "efivarfs",
+ "fusectl",
+ "hugetlbfs",
+ "mqueue",
+ "proc",
+ "pstore",
+ "ramfs",
+ "securityfs",
+ "sysfs",
+ "tmpfs",
+ "tracefs");
+}
+
+bool fstype_is_ro(const char *fstype) {
+ /* All Linux file systems that are necessarily read-only */
+ return STR_IN_SET(fstype,
+ "DM_verity_hash",
+ "iso9660",
+ "squashfs");
+}
+
+bool fstype_can_discard(const char *fstype) {
+ return STR_IN_SET(fstype,
+ "btrfs",
+ "ext4",
+ "vfat",
+ "xfs");
}
int repeat_unmount(const char *path, int flags) {
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
index 2e24a184c5..1e066d8886 100644
--- a/src/basic/mount-util.h
+++ b/src/basic/mount-util.h
@@ -44,6 +44,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
#define _cleanup_endmntent_ _cleanup_(endmntentp)
bool fstype_is_network(const char *fstype);
+bool fstype_is_api_vfs(const char *fstype);
+bool fstype_is_ro(const char *fsype);
+bool fstype_can_discard(const char *fstype);
union file_handle_union {
struct file_handle handle;
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index c08565aa3a..4e2bf7f6ff 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -59,7 +59,7 @@ int parse_pid(const char *s, pid_t* ret_pid) {
if ((unsigned long) pid != ul)
return -ERANGE;
- if (pid <= 0)
+ if (!pid_is_valid(pid))
return -ERANGE;
*ret_pid = pid;
@@ -152,7 +152,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
unsigned n_entries, start_pos = 0;
assert(t);
- assert(base == 1000 || base == 1024);
+ assert(IN_SET(base, 1000, 1024));
assert(size);
if (base == 1000) {
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 80fdda170f..6c06bd2acb 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -131,8 +131,7 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
/* Skip the common part. */
for (;;) {
- size_t a;
- size_t b;
+ size_t a, b;
from_dir += strspn(from_dir, "/");
to_path += strspn(to_path, "/");
@@ -144,7 +143,6 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
else
/* from_dir is a parent directory of to_path. */
r = strdup(to_path);
-
if (!r)
return -ENOMEM;
@@ -175,21 +173,32 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
/* Count the number of necessary ".." elements. */
for (n_parents = 0;;) {
+ size_t w;
+
from_dir += strspn(from_dir, "/");
if (!*from_dir)
break;
- from_dir += strcspn(from_dir, "/");
- n_parents++;
+ w = strcspn(from_dir, "/");
+
+ /* If this includes ".." we can't do a simple series of "..", refuse */
+ if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
+ return -EINVAL;
+
+ /* Count number of elements, except if they are "." */
+ if (w != 1 || from_dir[0] != '.')
+ n_parents++;
+
+ from_dir += w;
}
- r = malloc(n_parents * 3 + strlen(to_path) + 1);
+ r = new(char, n_parents * 3 + strlen(to_path) + 1);
if (!r)
return -ENOMEM;
- for (p = r; n_parents > 0; n_parents--, p += 3)
- memcpy(p, "../", 3);
+ for (p = r; n_parents > 0; n_parents--)
+ p = mempcpy(p, "../", 3);
strcpy(p, to_path);
path_kill_slashes(r);
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 26f165fc38..546246595c 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -30,7 +30,7 @@
#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin"
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
#else
# define DEFAULT_PATH DEFAULT_PATH_NORMAL
@@ -143,3 +143,13 @@ bool is_deviceallow_pattern(const char *path);
int systemd_installation_has_version(const char *root, unsigned minimal_version);
bool dot_or_dot_dot(const char *path);
+
+static inline const char *skip_dev_prefix(const char *p) {
+ const char *e;
+
+ /* Drop any /dev prefix if there is any */
+
+ e = path_startswith(p, "/dev/");
+
+ return e ?: p;
+}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index b80cacaa42..99b0946a03 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -34,7 +34,7 @@
#include <sys/wait.h>
#include <syslog.h>
#include <unistd.h>
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
@@ -312,19 +312,18 @@ int rename_process(const char name[]) {
/* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but
* has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at
* the end. This is the best option for changing /proc/self/cmdline. */
- if (mm_size < l+1) {
+
+ /* Let's not bother with this if we don't have euid == 0. Strictly speaking we should check for the
+ * CAP_SYS_RESOURCE capability which is independent of the euid. In our own code the capability generally is
+ * present only for euid == 0, hence let's use this as quick bypass check, to avoid calling mmap() if
+ * PR_SET_MM_ARG_{START,END} fails with EPERM later on anyway. After all geteuid() is dead cheap to call, but
+ * mmap() is not. */
+ if (geteuid() != 0)
+ log_debug("Skipping PR_SET_MM, as we don't have privileges.");
+ else if (mm_size < l+1) {
size_t nn_size;
char *nn;
- /* Let's not bother with this if we don't have euid == 0. Strictly speaking if people do weird stuff
- * with capabilities this could work even for euid != 0, but our own code generally doesn't do that,
- * hence let's use this as quick bypass check, to avoid calling mmap() if PR_SET_MM_ARG_START fails
- * with EPERM later on anyway. After all geteuid() is dead cheap to call, but mmap() is not. */
- if (geteuid() != 0) {
- log_debug("Skipping PR_SET_MM_ARG_START, as we don't have privileges.");
- goto use_saved_argv;
- }
-
nn_size = PAGE_ALIGN(l+1);
nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (nn == MAP_FAILED) {
@@ -351,9 +350,14 @@ int rename_process(const char name[]) {
mm = nn;
mm_size = nn_size;
- } else
+ } else {
strncpy(mm, name, mm_size);
+ /* Update the end pointer, continuing regardless of any failure. */
+ if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) mm + l + 1, 0, 0) < 0)
+ log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m");
+ }
+
use_saved_argv:
/* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if
* it still looks here */
@@ -388,7 +392,7 @@ int is_kernel_thread(pid_t pid) {
bool eof;
FILE *f;
- if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */
+ if (IN_SET(pid, 0, 1) || pid == getpid_cached()) /* pid 1, and we ourselves certainly aren't a kernel thread */
return 0;
assert(pid > 1);
@@ -471,6 +475,9 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
assert(field);
assert(uid);
+ if (pid < 0)
+ return -EINVAL;
+
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
if (!f) {
@@ -498,10 +505,22 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
}
int get_process_uid(pid_t pid, uid_t *uid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *uid = getuid();
+ return 0;
+ }
+
return get_process_id(pid, "Uid:", uid);
}
int get_process_gid(pid_t pid, gid_t *gid) {
+
+ if (pid == 0 || pid == getpid_cached()) {
+ *gid = getgid();
+ return 0;
+ }
+
assert_cc(sizeof(uid_t) == sizeof(gid_t));
return get_process_id(pid, "Gid:", gid);
}
@@ -577,7 +596,7 @@ int get_process_ppid(pid_t pid, pid_t *_ppid) {
assert(pid >= 0);
assert(_ppid);
- if (pid == 0) {
+ if (pid == 0 || pid == getpid_cached()) {
*_ppid = getppid();
return 0;
}
@@ -669,8 +688,7 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
log_debug("%s succeeded.", name);
return status.si_status;
- } else if (status.si_code == CLD_KILLED ||
- status.si_code == CLD_DUMPED) {
+ } else if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED)) {
log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
return -EPROTO;
@@ -775,6 +793,9 @@ bool pid_is_unwaited(pid_t pid) {
if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
return true;
+ if (pid == getpid_cached())
+ return true;
+
if (kill(pid, 0) >= 0)
return true;
@@ -792,8 +813,11 @@ bool pid_is_alive(pid_t pid) {
if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
return true;
+ if (pid == getpid_cached())
+ return true;
+
r = get_process_state(pid);
- if (r == -ESRCH || r == 'Z')
+ if (IN_SET(r, -ESRCH, 'Z'))
return false;
return true;
@@ -803,7 +827,10 @@ int pid_from_same_root_fs(pid_t pid) {
const char *root;
if (pid < 0)
- return 0;
+ return false;
+
+ if (pid == 0 || pid == getpid_cached())
+ return true;
root = procfs_file_alloca(pid, "root");
@@ -814,7 +841,7 @@ bool is_main_thread(void) {
static thread_local int cached = 0;
if (_unlikely_(cached == 0))
- cached = getpid() == gettid() ? 1 : -1;
+ cached = getpid_cached() == gettid() ? 1 : -1;
return cached > 0;
}
@@ -876,9 +903,50 @@ const char* personality_to_string(unsigned long p) {
return architecture_to_string(architecture);
}
+int safe_personality(unsigned long p) {
+ int ret;
+
+ /* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
+ * and in others as negative return value containing an errno-like value. Let's work around this: this is a
+ * wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
+ * the return value indicating the same issue, so that we are definitely on the safe side.
+ *
+ * See https://github.com/systemd/systemd/issues/6737 */
+
+ errno = 0;
+ ret = personality(p);
+ if (ret < 0) {
+ if (errno != 0)
+ return -errno;
+
+ errno = -ret;
+ }
+
+ return ret;
+}
+
+int opinionated_personality(unsigned long *ret) {
+ int current;
+
+ /* Returns the current personality, or PERSONALITY_INVALID if we can't determine it. This function is a bit
+ * opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
+ * two most relevant personalities: PER_LINUX and PER_LINUX32. */
+
+ current = safe_personality(PERSONALITY_INVALID);
+ if (current < 0)
+ return current;
+
+ if (((unsigned long) current & 0xffff) == PER_LINUX32)
+ *ret = PER_LINUX32;
+ else
+ *ret = PER_LINUX;
+
+ return 0;
+}
+
void valgrind_summary_hack(void) {
-#ifdef HAVE_VALGRIND_VALGRIND_H
- if (getpid() == 1 && RUNNING_ON_VALGRIND) {
+#if HAVE_VALGRIND_VALGRIND_H
+ if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
pid_t pid;
pid = raw_clone(SIGCHLD);
if (pid < 0)
@@ -922,6 +990,68 @@ int ioprio_parse_priority(const char *s, int *ret) {
return 0;
}
+/* The cached PID, possible values:
+ *
+ * == UNSET [0] → cache not initialized yet
+ * == BUSY [-1] → some thread is initializing it at the moment
+ * any other → the cached PID
+ */
+
+#define CACHED_PID_UNSET ((pid_t) 0)
+#define CACHED_PID_BUSY ((pid_t) -1)
+
+static pid_t cached_pid = CACHED_PID_UNSET;
+
+static void reset_cached_pid(void) {
+ /* Invoked in the child after a fork(), i.e. at the first moment the PID changed */
+ cached_pid = CACHED_PID_UNSET;
+}
+
+/* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc
+ * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against
+ * libpthread, as it is part of glibc anyway. */
+extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void * __dso_handle);
+extern void* __dso_handle __attribute__ ((__weak__));
+
+pid_t getpid_cached(void) {
+ pid_t current_value;
+
+ /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
+ * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally
+ * cached. Starting with 2.24 getpid() started to become prohibitively expensive when used for detecting when
+ * objects were used across fork()s. With this caching the old behaviour is somewhat restored.
+ *
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1443976
+ * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e
+ */
+
+ current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY);
+
+ switch (current_value) {
+
+ case CACHED_PID_UNSET: { /* Not initialized yet, then do so now */
+ pid_t new_pid;
+
+ new_pid = getpid();
+
+ if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
+ /* OOM? Let's try again later */
+ cached_pid = CACHED_PID_UNSET;
+ return new_pid;
+ }
+
+ cached_pid = new_pid;
+ return new_pid;
+ }
+
+ case CACHED_PID_BUSY: /* Somebody else is currently initializing */
+ return getpid();
+
+ default: /* Properly initialized */
+ return current_value;
+ }
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index 28d8d7499a..82af2f9181 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -20,6 +20,7 @@
***/
#include <alloca.h>
+#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
@@ -90,6 +91,9 @@ bool oom_score_adjust_is_valid(int oa);
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
+int safe_personality(unsigned long p);
+int opinionated_personality(unsigned long *ret);
+
int ioprio_class_to_string_alloc(int i, char **s);
int ioprio_class_from_string(const char *s);
@@ -110,6 +114,14 @@ static inline bool nice_is_valid(int n) {
return n >= PRIO_MIN && n < PRIO_MAX;
}
+static inline bool sched_policy_is_valid(int i) {
+ return IN_SET(i, SCHED_OTHER, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR);
+}
+
+static inline bool sched_priority_is_valid(int i) {
+ return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
+}
+
static inline bool ioprio_class_is_valid(int i) {
return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
}
@@ -118,4 +130,10 @@ static inline bool ioprio_priority_is_valid(int i) {
return i >= 0 && i < IOPRIO_BE_NR;
}
+static inline bool pid_is_valid(pid_t p) {
+ return p > 0;
+}
+
int ioprio_parse_priority(const char *s, int *ret);
+
+pid_t getpid_cached(void);
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index 810eeab4d5..146c8f55ed 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -26,11 +26,11 @@
#include <linux/random.h>
#include <stdint.h>
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
# include <sys/auxv.h>
#endif
-#ifdef USE_SYS_RANDOM_H
+#if USE_SYS_RANDOM_H
# include <sys/random.h>
#else
# include <linux/random.h>
@@ -64,7 +64,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
if ((size_t) r == n)
return 0;
if (!high_quality_required) {
- /* Fill in the remaing bytes using pseudorandom values */
+ /* Fill in the remaining bytes using pseudorandom values */
pseudorandom_bytes((uint8_t*) p + r, n - r);
return 0;
}
@@ -100,14 +100,14 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) {
void initialize_srand(void) {
static bool srand_called = false;
unsigned x;
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
void *auxv;
#endif
if (srand_called)
return;
-#ifdef HAVE_SYS_AUXV_H
+#if HAVE_SYS_AUXV_H
/* The kernel provides us with 16 bytes of entropy in auxv, so let's
* try to make use of that to seed the pseudo-random generator. It's
* better than nothing... */
diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c
index 0d21423a9c..d2642812e7 100644
--- a/src/basic/replace-var.c
+++ b/src/basic/replace-var.c
@@ -54,7 +54,7 @@ static int get_variable(const char *b, char **r) {
return 1;
}
-char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata) {
+char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata) {
char *r, *t;
const char *f;
size_t l;
diff --git a/src/basic/replace-var.h b/src/basic/replace-var.h
index 78412910b2..31eb057803 100644
--- a/src/basic/replace-var.h
+++ b/src/basic/replace-var.h
@@ -19,4 +19,4 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata);
+char *replace_var(const char *text, char *(*lookup)(const char *variable, void *userdata), void *userdata);
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
index ca834df621..5c41429f01 100644
--- a/src/basic/rlimit-util.c
+++ b/src/basic/rlimit-util.c
@@ -42,7 +42,8 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
/* So we failed to set the desired setrlimit, then let's try
* to get as close as we can */
- assert_se(getrlimit(resource, &highest) == 0);
+ if (getrlimit(resource, &highest) < 0)
+ return -errno;
fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index 3f80ed263a..0bbafb4cd7 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -132,7 +132,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
- if (r != -ENOTTY && r != -EINVAL) {
+ if (!IN_SET(r, -ENOTTY, -EINVAL)) {
if (ret == 0)
ret = r;
@@ -193,7 +193,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
if (r >= 0)
return r;
- if (r != -ENOTTY && r != -EINVAL && r != -ENOTDIR)
+ if (!IN_SET(r, -ENOTTY, -EINVAL, -ENOTDIR))
return r;
/* Not btrfs or not a subvolume */
@@ -202,7 +202,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
if (fd < 0) {
- if (errno != ENOTDIR && errno != ELOOP)
+ if (!IN_SET(errno, ENOTDIR, ELOOP))
return -errno;
if (!(flags & REMOVE_PHYSICAL)) {
diff --git a/src/basic/securebits-util.c b/src/basic/securebits-util.c
new file mode 100644
index 0000000000..011ec36af4
--- /dev/null
+++ b/src/basic/securebits-util.c
@@ -0,0 +1,84 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Yu Watanabe
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "securebits.h"
+#include "securebits-util.h"
+#include "string-util.h"
+
+int secure_bits_to_string_alloc(int i, char **s) {
+ _cleanup_free_ char *str = NULL;
+ size_t len;
+ int r;
+
+ assert(s);
+
+ r = asprintf(&str, "%s%s%s%s%s%s",
+ (i & (1 << SECURE_KEEP_CAPS)) ? "keep-caps " : "",
+ (i & (1 << SECURE_KEEP_CAPS_LOCKED)) ? "keep-caps-locked " : "",
+ (i & (1 << SECURE_NO_SETUID_FIXUP)) ? "no-setuid-fixup " : "",
+ (i & (1 << SECURE_NO_SETUID_FIXUP_LOCKED)) ? "no-setuid-fixup-locked " : "",
+ (i & (1 << SECURE_NOROOT)) ? "noroot " : "",
+ (i & (1 << SECURE_NOROOT_LOCKED)) ? "noroot-locked " : "");
+ if (r < 0)
+ return -ENOMEM;
+
+ len = strlen(str);
+ if (len != 0)
+ str[len - 1] = '\0';
+
+ *s = str;
+ str = NULL;
+
+ return 0;
+}
+
+int secure_bits_from_string(const char *s) {
+ int secure_bits = 0;
+ const char *p;
+ int r;
+
+ for (p = s;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return r;
+ if (r <= 0)
+ break;
+
+ if (streq(word, "keep-caps"))
+ secure_bits |= 1 << SECURE_KEEP_CAPS;
+ else if (streq(word, "keep-caps-locked"))
+ secure_bits |= 1 << SECURE_KEEP_CAPS_LOCKED;
+ else if (streq(word, "no-setuid-fixup"))
+ secure_bits |= 1 << SECURE_NO_SETUID_FIXUP;
+ else if (streq(word, "no-setuid-fixup-locked"))
+ secure_bits |= 1 << SECURE_NO_SETUID_FIXUP_LOCKED;
+ else if (streq(word, "noroot"))
+ secure_bits |= 1 << SECURE_NOROOT;
+ else if (streq(word, "noroot-locked"))
+ secure_bits |= 1 << SECURE_NOROOT_LOCKED;
+ }
+
+ return secure_bits;
+}
diff --git a/src/basic/securebits-util.h b/src/basic/securebits-util.h
new file mode 100644
index 0000000000..b4d970c366
--- /dev/null
+++ b/src/basic/securebits-util.h
@@ -0,0 +1,28 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Yu Watanabe
+
+ 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 "securebits.h"
+
+int secure_bits_to_string_alloc(int i, char **s);
+int secure_bits_from_string(const char *s);
+static inline bool secure_bits_is_valid(int i) {
+ return ((SECURE_ALL_BITS | SECURE_ALL_LOCKS) & i) == i;
+}
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index 139e6e21e3..93bcdb2160 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -26,7 +26,7 @@
#include <sys/un.h>
#include <syslog.h>
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/context.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
@@ -40,7 +40,7 @@
#include "time-util.h"
#include "util.h"
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
@@ -54,7 +54,7 @@ static struct selabel_handle *label_hnd = NULL;
#endif
bool mac_selinux_use(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (cached_use < 0)
cached_use = is_selinux_enabled() > 0;
@@ -65,7 +65,7 @@ bool mac_selinux_use(void) {
}
void mac_selinux_retest(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
cached_use = -1;
#endif
}
@@ -73,7 +73,7 @@ void mac_selinux_retest(void) {
int mac_selinux_init(void) {
int r = 0;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
@@ -110,7 +110,7 @@ int mac_selinux_init(void) {
void mac_selinux_finish(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!label_hnd)
return;
@@ -121,7 +121,7 @@ void mac_selinux_finish(void) {
int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
struct stat st;
int r;
@@ -169,7 +169,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
int mac_selinux_apply(const char *path, const char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
@@ -188,7 +188,7 @@ int mac_selinux_apply(const char *path, const char *label) {
int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
int r = -EOPNOTSUPP;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
@@ -220,7 +220,7 @@ int mac_selinux_get_our_label(char **label) {
assert(label);
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return -EOPNOTSUPP;
@@ -235,7 +235,7 @@ int mac_selinux_get_our_label(char **label) {
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
int r = -EOPNOTSUPP;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
security_class_t sclass;
@@ -296,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
char* mac_selinux_free(char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!label)
return NULL;
@@ -312,7 +312,7 @@ char* mac_selinux_free(char *label) {
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *filecon = NULL;
int r;
@@ -355,7 +355,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
void mac_selinux_create_file_clear(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
@@ -367,7 +367,7 @@ void mac_selinux_create_file_clear(void) {
int mac_selinux_create_socket_prepare(const char *label) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (!mac_selinux_use())
return 0;
@@ -386,7 +386,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
void mac_selinux_create_socket_clear(void) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
PROTECT_ERRNO;
if (!mac_selinux_use())
@@ -400,7 +400,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
/* Binds a socket and label its file system object according to the SELinux policy */
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_cleanup_freecon_ char *fcon = NULL;
const struct sockaddr_un *un;
bool context_changed = false;
diff --git a/src/basic/set.c b/src/basic/set.c
new file mode 100644
index 0000000000..fd398b8212
--- /dev/null
+++ b/src/basic/set.c
@@ -0,0 +1,61 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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 "set.h"
+
+int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...) {
+ _cleanup_set_free_ Set *s = NULL;
+ int r;
+
+ assert(ret);
+
+ s = set_new(hash_ops HASHMAP_DEBUG_PASS_ARGS);
+ if (!s)
+ return -ENOMEM;
+
+ if (add) {
+ va_list ap;
+
+ r = set_put(s, add);
+ if (r < 0)
+ return r;
+
+ va_start(ap, add);
+
+ for(;;) {
+ void *arg = va_arg(ap, void*);
+
+ if (!arg)
+ break;
+
+ r = set_put(s, arg);
+ if (r < 0) {
+ va_end(ap);
+ return r;
+ }
+ }
+
+ va_end(ap);
+ }
+
+ *ret = s;
+ s = NULL;
+
+ return 0;
+}
diff --git a/src/basic/set.h b/src/basic/set.h
index a5f8beb0c4..12d0fda1ca 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -136,3 +136,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...);
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index 280b5c3251..df6b742fde 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -38,7 +38,7 @@ int reset_all_signal_handlers(void) {
for (sig = 1; sig < _NSIG; sig++) {
/* These two cannot be caught... */
- if (sig == SIGKILL || sig == SIGSTOP)
+ if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
/* On Linux the first two RT signals are reserved by
diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
index 206dde3881..7bed6bd4fe 100644
--- a/src/basic/smack-util.c
+++ b/src/basic/smack-util.c
@@ -35,7 +35,7 @@
#include "string-table.h"
#include "xattr-util.h"
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
bool mac_smack_use(void) {
static int cached_use = -1;
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index 6d1dc83874..6e7cdaac63 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -83,7 +83,7 @@ int socket_address_listen(
return -errno;
}
- if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) {
+ if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
if (bind_to_device)
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
return -errno;
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 016e64aa03..29c779552d 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -48,7 +48,7 @@
#include "utf8.h"
#include "util.h"
-#ifdef ENABLE_IDN
+#if ENABLE_IDN
# define IDN_FLAGS (NI_IDN|NI_IDN_USE_STD3_ASCII_RULES)
#else
# define IDN_FLAGS 0
@@ -268,7 +268,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->sockaddr.in.sin_port == 0)
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -280,7 +280,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->sockaddr.in6.sin6_port == 0)
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -304,7 +304,7 @@ int socket_address_verify(const SocketAddress *a) {
}
}
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
return -EINVAL;
return 0;
@@ -314,7 +314,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->size != sizeof(struct sockaddr_nl))
return -EINVAL;
- if (a->type != SOCK_RAW && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -323,7 +323,7 @@ int socket_address_verify(const SocketAddress *a) {
if (a->size != sizeof(struct sockaddr_vm))
return -EINVAL;
- if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM)
+ if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL;
return 0;
@@ -364,8 +364,7 @@ bool socket_address_can_accept(const SocketAddress *a) {
assert(a);
return
- a->type == SOCK_STREAM ||
- a->type == SOCK_SEQPACKET;
+ IN_SET(a->type, SOCK_STREAM, SOCK_SEQPACKET);
}
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
@@ -793,7 +792,8 @@ static const char* const netlink_family_table[] = {
[NETLINK_KOBJECT_UEVENT] = "kobject-uevent",
[NETLINK_GENERIC] = "generic",
[NETLINK_SCSITRANSPORT] = "scsitransport",
- [NETLINK_ECRYPTFS] = "ecryptfs"
+ [NETLINK_ECRYPTFS] = "ecryptfs",
+ [NETLINK_RDMA] = "rdma",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX);
@@ -892,7 +892,7 @@ bool ifname_valid(const char *p) {
if ((unsigned char) *p <= 32U)
return false;
- if (*p == ':' || *p == '/')
+ if (IN_SET(*p, ':', '/'))
return false;
numeric = numeric && (*p >= '0' && *p <= '9');
@@ -1080,7 +1080,7 @@ ssize_t next_datagram_size_fd(int fd) {
l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
if (l < 0) {
- if (errno == EOPNOTSUPP || errno == EFAULT)
+ if (IN_SET(errno, EOPNOTSUPP, EFAULT))
goto fallback;
return -errno;
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 73c3a339fc..43edc05c63 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <linux/netlink.h>
+#include <linux/if_infiniband.h>
#include <linux/if_packet.h>
#include "macro.h"
@@ -42,6 +43,8 @@ union sockaddr_union {
struct sockaddr_storage storage;
struct sockaddr_ll ll;
struct sockaddr_vm vm;
+ /* Ensure there is enough space to store Infiniband addresses */
+ uint8_t ll_buffer[offsetof(struct sockaddr_ll, sll_addr) + CONST_MAX(ETH_ALEN, INFINIBAND_ALEN)];
};
typedef struct SocketAddress {
@@ -147,6 +150,23 @@ int flush_accept(int fd);
struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length);
+/*
+ * Certain hardware address types (e.g Infiniband) do not fit into sll_addr
+ * (8 bytes) and run over the structure. This macro returns the correct size that
+ * must be passed to kernel.
+ */
+#define SOCKADDR_LL_LEN(sa) \
+ ({ \
+ const struct sockaddr_ll *_sa = &(sa); \
+ size_t _mac_len = sizeof(_sa->sll_addr); \
+ assert(_sa->sll_family == AF_PACKET); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_ETHER) \
+ _mac_len = MAX(_mac_len, (size_t) ETH_ALEN); \
+ if (be16toh(_sa->sll_hatype) == ARPHRD_INFINIBAND) \
+ _mac_len = MAX(_mac_len, (size_t) INFINIBAND_ALEN); \
+ offsetof(struct sockaddr_ll, sll_addr) + _mac_len; \
+ })
+
/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
#define SOCKADDR_UN_LEN(sa) \
({ \
diff --git a/src/basic/special.h b/src/basic/special.h
index 48b36de557..012ac8d9c2 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -46,7 +46,6 @@
/* Early boot targets */
#define SPECIAL_SYSINIT_TARGET "sysinit.target"
#define SPECIAL_SOCKETS_TARGET "sockets.target"
-#define SPECIAL_BUSNAMES_TARGET "busnames.target"
#define SPECIAL_TIMERS_TARGET "timers.target"
#define SPECIAL_PATHS_TARGET "paths.target"
#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 9d2f4bc8f9..3179fba3ba 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -215,7 +215,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) {
}
char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+ return strnappend(s, suffix, strlen_ptr(suffix));
}
char *strjoin_real(const char *x, ...) {
@@ -542,7 +542,7 @@ char *ellipsize(const char *s, size_t length, unsigned percent) {
return ellipsize_mem(s, strlen(s), length, percent);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
+bool nulstr_contains(const char *nulstr, const char *needle) {
const char *i;
if (!nulstr)
@@ -558,7 +558,7 @@ bool nulstr_contains(const char*nulstr, const char *needle) {
char* strshorten(char *s, size_t l) {
assert(s);
- if (l < strlen(s))
+ if (strnlen(s, l+1) > l)
s[l] = 0;
return s;
@@ -635,6 +635,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
if (!f)
return NULL;
+ /* Note we use the _unlocked() stdio variants on f for performance
+ * reasons. It's safe to do so since we created f here and it
+ * doesn't leave our scope.
+ */
+
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
switch (state) {
@@ -645,21 +650,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
- fputs(" ", f);
+ fputs_unlocked(" ", f);
else
- fputc(*i, f);
+ fputc_unlocked(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
+ fputc_unlocked('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
- fputc('\x1B', f);
- fputc(*i, f);
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked(*i, f);
state = STATE_OTHER;
}
@@ -668,9 +673,9 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
case STATE_BRACKET:
if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
+ (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
+ fputc_unlocked('\x1B', f);
+ fputc_unlocked('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
@@ -702,7 +707,7 @@ char *strextend(char **x, ...) {
assert(x);
- l = f = *x ? strlen(*x) : 0;
+ l = f = strlen_ptr(*x);
va_start(ap, x);
for (;;) {
@@ -821,7 +826,7 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
/*
* Pointer to memset is volatile so that compiler must de-reference
* the pointer and can't assume that it points to any function in
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index be44dedff4..4c94b182c1 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -120,7 +120,7 @@ char *strjoin_real(const char *x, ...) _sentinel_;
({ \
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
- int _len_ = 0; \
+ size_t _len_ = 0; \
unsigned _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
@@ -158,7 +158,7 @@ bool string_has_cc(const char *p, const char *ok) _pure_;
char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
char *ellipsize(const char *s, size_t length, unsigned percent);
-bool nulstr_contains(const char*nulstr, const char *needle);
+bool nulstr_contains(const char *nulstr, const char *needle);
char* strshorten(char *s, size_t l);
@@ -189,7 +189,7 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const
return memmem(haystack, haystacklen, needle, needlelen);
}
-#if !HAVE_DECL_EXPLICIT_BZERO
+#if !HAVE_EXPLICIT_BZERO
void explicit_bzero(void *p, size_t l);
#endif
@@ -200,3 +200,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
bool string_is_safe(const char *p) _pure_;
+
+static inline size_t strlen_ptr(const char *s) {
+ if (!s)
+ return 0;
+
+ return strlen(s);
+}
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index 9a8ef825c5..28c8c35fe0 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -55,6 +55,7 @@
#include "terminal-util.h"
#include "time-util.h"
#include "util.h"
+#include "path-util.h"
static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0;
@@ -244,6 +245,7 @@ int ask_string(char **ret, const char *text, ...) {
int reset_terminal_fd(int fd, bool switch_to_text) {
struct termios termios;
+ _cleanup_free_ char *utf8 = NULL;
int r = 0;
/* Set terminal to some sane defaults */
@@ -261,8 +263,8 @@ int reset_terminal_fd(int fd, bool switch_to_text) {
if (switch_to_text)
(void) ioctl(fd, KDSETMODE, KD_TEXT);
- /* Enable console unicode mode */
- (void) ioctl(fd, KDSKBMODE, K_UNICODE);
+ /* Set default keyboard mode */
+ (void) vt_reset_keyboard(fd);
if (tcgetattr(fd, &termios) < 0) {
r = -errno;
@@ -474,7 +476,7 @@ int acquire_terminal(
l = read(notify, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
@@ -556,6 +558,7 @@ int terminal_vhangup(const char *name) {
int vt_disallocate(const char *name) {
_cleanup_close_ int fd = -1;
+ const char *e, *n;
unsigned u;
int r;
@@ -563,7 +566,8 @@ int vt_disallocate(const char *name) {
* (i.e. because it is the active one), at least clear it
* entirely (including the scrollback buffer) */
- if (!startswith(name, "/dev/"))
+ e = path_startswith(name, "/dev/");
+ if (!e)
return -EINVAL;
if (!tty_is_vc(name)) {
@@ -582,10 +586,11 @@ int vt_disallocate(const char *name) {
return 0;
}
- if (!startswith(name, "/dev/tty"))
+ n = startswith(e, "tty");
+ if (!n)
return -EINVAL;
- r = safe_atou(name+8, &u);
+ r = safe_atou(n, &u);
if (r < 0)
return r;
@@ -649,10 +654,7 @@ bool tty_is_vc(const char *tty) {
bool tty_is_console(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- return streq(tty, "console");
+ return streq(skip_dev_prefix(tty), "console");
}
int vtnr_from_tty(const char *tty) {
@@ -660,8 +662,7 @@ int vtnr_from_tty(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
+ tty = skip_dev_prefix(tty);
if (!startswith(tty, "tty") )
return -EINVAL;
@@ -775,8 +776,7 @@ bool tty_is_vc_resolve(const char *tty) {
assert(tty);
- if (startswith(tty, "/dev/"))
- tty += 5;
+ tty = skip_dev_prefix(tty);
if (streq(tty, "console")) {
tty = resolve_dev_console(&active);
@@ -918,11 +918,9 @@ int getttyname_malloc(int fd, char **ret) {
r = ttyname_r(fd, path, sizeof(path));
if (r == 0) {
- const char *p;
char *c;
- p = startswith(path, "/dev/");
- c = strdup(p ?: path);
+ c = strdup(skip_dev_prefix(path));
if (!c)
return -ENOMEM;
@@ -1220,7 +1218,7 @@ bool colors_enabled(void) {
val = getenv_bool("SYSTEMD_COLORS");
if (val >= 0)
enabled = val;
- else if (getpid() == 1)
+ else if (getpid_cached() == 1)
/* PID1 outputs to the console without holding it open all the time */
enabled = !getenv_terminal_is_dumb();
else
@@ -1229,3 +1227,44 @@ bool colors_enabled(void) {
return enabled;
}
+
+bool underline_enabled(void) {
+ static int enabled = -1;
+
+ if (enabled < 0) {
+
+ /* The Linux console doesn't support underlining, turn it off, but only there. */
+
+ if (!colors_enabled())
+ enabled = false;
+ else
+ enabled = !streq_ptr(getenv("TERM"), "linux");
+ }
+
+ return enabled;
+}
+
+int vt_default_utf8(void) {
+ _cleanup_free_ char *b = NULL;
+ int r;
+
+ /* Read the default VT UTF8 setting from the kernel */
+
+ r = read_one_line_file("/sys/module/vt/parameters/default_utf8", &b);
+ if (r < 0)
+ return r;
+
+ return parse_boolean(b);
+}
+
+int vt_reset_keyboard(int fd) {
+ int kb;
+
+ /* If we can't read the default, then default to unicode. It's 2017 after all. */
+ kb = vt_default_utf8() != 0 ? K_UNICODE : K_XLATE;
+
+ if (ioctl(fd, KDSKBMODE, kb) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index b862bfaf05..c3045eb09d 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -86,6 +86,7 @@ void columns_lines_cache_reset(int _unused_ signum);
bool on_tty(void);
bool terminal_is_dumb(void);
bool colors_enabled(void);
+bool underline_enabled(void);
#define DEFINE_ANSI_FUNC(name, NAME) \
static inline const char *ansi_##name(void) { \
@@ -93,19 +94,28 @@ bool colors_enabled(void);
} \
struct __useless_struct_to_allow_trailing_semicolon__
-DEFINE_ANSI_FUNC(underline, UNDERLINE);
+#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME, REPLACEMENT) \
+ static inline const char *ansi_##name(void) { \
+ return underline_enabled() ? ANSI_##NAME : \
+ colors_enabled() ? ANSI_##REPLACEMENT : ""; \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+
DEFINE_ANSI_FUNC(highlight, HIGHLIGHT);
-DEFINE_ANSI_FUNC(highlight_underline, HIGHLIGHT_UNDERLINE);
DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED);
DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN);
DEFINE_ANSI_FUNC(highlight_yellow, HIGHLIGHT_YELLOW);
DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE);
-DEFINE_ANSI_FUNC(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE);
-DEFINE_ANSI_FUNC(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE);
DEFINE_ANSI_FUNC(normal, NORMAL);
+DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
+DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE, HIGHLIGHT_BLUE);
+
int get_ctty_devnr(pid_t pid, dev_t *d);
int get_ctty(pid_t, dev_t *_devnr, char **r);
@@ -117,3 +127,6 @@ int ptsname_namespace(int pty, char **ret);
int openpt_in_namespace(pid_t pid, int flags);
int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
+
+int vt_default_utf8(void);
+int vt_reset_keyboard(int fd);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 68ba86f6a5..f7f5e614f2 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -21,6 +21,7 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/timerfd.h>
@@ -596,7 +597,7 @@ int timestamp_deserialize(const char *value, usec_t *timestamp) {
return r;
}
-int parse_timestamp(const char *t, usec_t *usec) {
+static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
static const struct {
const char *name;
const int nr;
@@ -617,7 +618,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
{ "Sat", 6 },
};
- const char *k, *utc, *tzn = NULL;
+ const char *k, *utc = NULL, *tzn = NULL;
struct tm tm, copy;
time_t x;
usec_t x_usec, plus = 0, minus = 0, ret;
@@ -645,84 +646,86 @@ int parse_timestamp(const char *t, usec_t *usec) {
assert(t);
assert(usec);
- if (t[0] == '@')
+ if (t[0] == '@' && !with_tz)
return parse_sec(t + 1, usec);
ret = now(CLOCK_REALTIME);
- if (streq(t, "now"))
- goto finish;
+ if (!with_tz) {
+ if (streq(t, "now"))
+ goto finish;
- else if (t[0] == '+') {
- r = parse_sec(t+1, &plus);
- if (r < 0)
- return r;
+ else if (t[0] == '+') {
+ r = parse_sec(t+1, &plus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if (t[0] == '-') {
- r = parse_sec(t+1, &minus);
- if (r < 0)
- return r;
+ } else if (t[0] == '-') {
+ r = parse_sec(t+1, &minus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if ((k = endswith(t, " ago"))) {
- t = strndupa(t, k - t);
+ } else if ((k = endswith(t, " ago"))) {
+ t = strndupa(t, k - t);
- r = parse_sec(t, &minus);
- if (r < 0)
- return r;
+ r = parse_sec(t, &minus);
+ if (r < 0)
+ return r;
- goto finish;
+ goto finish;
- } else if ((k = endswith(t, " left"))) {
- t = strndupa(t, k - t);
+ } else if ((k = endswith(t, " left"))) {
+ t = strndupa(t, k - t);
- r = parse_sec(t, &plus);
- if (r < 0)
- return r;
+ r = parse_sec(t, &plus);
+ if (r < 0)
+ return r;
- goto finish;
- }
+ goto finish;
+ }
- /* See if the timestamp is suffixed with UTC */
- utc = endswith_no_case(t, " UTC");
- if (utc)
- t = strndupa(t, utc - t);
- else {
- const char *e = NULL;
- int j;
+ /* See if the timestamp is suffixed with UTC */
+ utc = endswith_no_case(t, " UTC");
+ if (utc)
+ t = strndupa(t, utc - t);
+ else {
+ const char *e = NULL;
+ int j;
- tzset();
+ tzset();
- /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
- * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
- * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
- * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
- * support arbitrary timezone specifications. */
+ /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only
+ * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because
+ * there are no nice APIs available to cover this. By accepting the local time zone strings, we make
+ * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't
+ * support arbitrary timezone specifications. */
- for (j = 0; j <= 1; j++) {
+ for (j = 0; j <= 1; j++) {
- if (isempty(tzname[j]))
- continue;
+ if (isempty(tzname[j]))
+ continue;
- e = endswith_no_case(t, tzname[j]);
- if (!e)
- continue;
- if (e == t)
- continue;
- if (e[-1] != ' ')
- continue;
+ e = endswith_no_case(t, tzname[j]);
+ if (!e)
+ continue;
+ if (e == t)
+ continue;
+ if (e[-1] != ' ')
+ continue;
- break;
- }
+ break;
+ }
- if (IN_SET(j, 0, 1)) {
- /* Found one of the two timezones specified. */
- t = strndupa(t, e - t - 1);
- dst = j;
- tzn = tzname[j];
+ if (IN_SET(j, 0, 1)) {
+ /* Found one of the two timezones specified. */
+ t = strndupa(t, e - t - 1);
+ dst = j;
+ tzn = tzname[j];
+ }
}
}
@@ -733,7 +736,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
return -EINVAL;
tm.tm_isdst = dst;
- if (tzn)
+ if (!with_tz && tzn)
tm.tm_zone = tzn;
if (streq(t, "today")) {
@@ -846,11 +849,11 @@ parse_usec:
}
from_tm:
- x = mktime_or_timegm(&tm, utc);
- if (x < 0)
+ if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
- if (weekday >= 0 && tm.tm_wday != weekday)
+ x = mktime_or_timegm(&tm, utc);
+ if (x < 0)
return -EINVAL;
ret = (usec_t) x * USEC_PER_SEC + x_usec;
@@ -874,6 +877,75 @@ finish:
return 0;
}
+typedef struct ParseTimestampResult {
+ usec_t usec;
+ int return_value;
+} ParseTimestampResult;
+
+int parse_timestamp(const char *t, usec_t *usec) {
+ char *last_space, *tz = NULL;
+ ParseTimestampResult *shared, tmp;
+ int r;
+ pid_t pid;
+
+ last_space = strrchr(t, ' ');
+ if (last_space != NULL && timezone_is_valid(last_space + 1))
+ tz = last_space + 1;
+
+ if (tz == NULL || endswith_no_case(t, " UTC"))
+ return parse_timestamp_impl(t, usec, false);
+
+ shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (shared == MAP_FAILED)
+ return negative_errno();
+
+ pid = fork();
+
+ if (pid == -1) {
+ int fork_errno = errno;
+ (void) munmap(shared, sizeof *shared);
+ return -fork_errno;
+ }
+
+ if (pid == 0) {
+ bool with_tz = true;
+
+ if (setenv("TZ", tz, 1) != 0) {
+ shared->return_value = negative_errno();
+ _exit(EXIT_FAILURE);
+ }
+
+ tzset();
+
+ /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation.
+ * Otherwise just cut it off */
+ with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]);
+
+ /*cut off the timezone if we dont need it*/
+ if (with_tz)
+ t = strndupa(t, last_space - t);
+
+ shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = wait_for_terminate(pid, NULL);
+ if (r < 0) {
+ (void) munmap(shared, sizeof *shared);
+ return r;
+ }
+
+ tmp = *shared;
+ if (munmap(shared, sizeof *shared) != 0)
+ return negative_errno();
+
+ if (tmp.return_value == 0)
+ *usec = tmp.usec;
+
+ return tmp.return_value;
+}
+
static char* extract_multiplier(char *p, usec_t *multiplier) {
static const struct {
const char *suffix;
@@ -1010,7 +1082,11 @@ int parse_sec(const char *t, usec_t *usec) {
}
int parse_sec_fix_0(const char *t, usec_t *usec) {
+ assert(t);
+ assert(usec);
+
t += strspn(t, WHITESPACE);
+
if (streq(t, "0")) {
*usec = USEC_INFINITY;
return 0;
@@ -1236,7 +1312,7 @@ bool timezone_is_valid(const char *name) {
if (!(*p >= '0' && *p <= '9') &&
!(*p >= 'a' && *p <= 'z') &&
!(*p >= 'A' && *p <= 'Z') &&
- !(*p == '-' || *p == '_' || *p == '+' || *p == '/'))
+ !IN_SET(*p, '-', '_', '+', '/'))
return false;
if (*p == '/') {
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 920ca0d9f5..f9c034c94b 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -305,7 +305,7 @@ static char *do_escape(const char *f, char *t) {
for (; *f; f++) {
if (*f == '/')
*(t++) = '-';
- else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
+ else if (IN_SET(*f, '-', '\\') || !strchr(VALID_CHARS, *f))
t = do_escape_char(*f, t);
else
*(t++) = *f;
@@ -608,7 +608,6 @@ const char* unit_dbus_interface_from_type(UnitType t) {
static const char *const table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
[UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
- [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
[UNIT_TARGET] = "org.freedesktop.systemd1.Target",
[UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
[UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
@@ -839,7 +838,6 @@ bool slice_name_is_valid(const char *name) {
static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "service",
[UNIT_SOCKET] = "socket",
- [UNIT_BUSNAME] = "busname",
[UNIT_TARGET] = "target",
[UNIT_DEVICE] = "device",
[UNIT_MOUNT] = "mount",
@@ -884,19 +882,6 @@ static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = "dead",
- [BUSNAME_MAKING] = "making",
- [BUSNAME_REGISTERED] = "registered",
- [BUSNAME_LISTENING] = "listening",
- [BUSNAME_RUNNING] = "running",
- [BUSNAME_SIGTERM] = "sigterm",
- [BUSNAME_SIGKILL] = "sigkill",
- [BUSNAME_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
-
static const char* const device_state_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = "dead",
[DEVICE_TENTATIVE] = "tentative",
@@ -912,8 +897,6 @@ static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
[MOUNT_MOUNTED] = "mounted",
[MOUNT_REMOUNTING] = "remounting",
[MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
[MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
[MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
[MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
@@ -995,8 +978,6 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = {
[SWAP_ACTIVATING_DONE] = "activating-done",
[SWAP_ACTIVE] = "active",
[SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
[SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
[SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
[SWAP_FAILED] = "failed"
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index 0f164a6aa9..15558b4fbd 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -28,7 +28,6 @@
typedef enum UnitType {
UNIT_SERVICE = 0,
UNIT_SOCKET,
- UNIT_BUSNAME,
UNIT_TARGET,
UNIT_DEVICE,
UNIT_MOUNT,
@@ -73,19 +72,6 @@ typedef enum AutomountState {
_AUTOMOUNT_STATE_INVALID = -1
} AutomountState;
-typedef enum BusNameState {
- BUSNAME_DEAD,
- BUSNAME_MAKING,
- BUSNAME_REGISTERED,
- BUSNAME_LISTENING,
- BUSNAME_RUNNING,
- BUSNAME_SIGTERM,
- BUSNAME_SIGKILL,
- BUSNAME_FAILED,
- _BUSNAME_STATE_MAX,
- _BUSNAME_STATE_INVALID = -1
-} BusNameState;
-
/* We simply watch devices, we cannot plug/unplug them. That
* simplifies the state engine greatly */
typedef enum DeviceState {
@@ -103,8 +89,6 @@ typedef enum MountState {
MOUNT_MOUNTED,
MOUNT_REMOUNTING,
MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM,
MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM,
@@ -186,8 +170,6 @@ typedef enum SwapState {
SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
SWAP_ACTIVE,
SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
SWAP_DEACTIVATING_SIGTERM,
SWAP_DEACTIVATING_SIGKILL,
SWAP_FAILED,
@@ -339,9 +321,6 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_;
const char* automount_state_to_string(AutomountState i) _const_;
AutomountState automount_state_from_string(const char *s) _pure_;
-const char* busname_state_to_string(BusNameState i) _const_;
-BusNameState busname_state_from_string(const char *s) _pure_;
-
const char* device_state_to_string(DeviceState i) _const_;
DeviceState device_state_from_string(const char *s) _pure_;
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index c619dad527..a691a0d3fc 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -543,8 +543,7 @@ bool valid_user_group_name(const char *u) {
if (!(*i >= 'a' && *i <= 'z') &&
!(*i >= 'A' && *i <= 'Z') &&
!(*i >= '0' && *i <= '9') &&
- *i != '_' &&
- *i != '-')
+ !IN_SET(*i, '_', '-'))
return false;
}
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 6eae2b983d..7a52fac621 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -73,7 +73,7 @@ static bool unichar_is_control(char32_t ch) {
'\t' is in C0 range, but more or less harmless and commonly used.
*/
- return (ch < ' ' && ch != '\t' && ch != '\n') ||
+ return (ch < ' ' && !IN_SET(ch, '\t', '\n')) ||
(0x7F <= ch && ch <= 0x9F);
}
diff --git a/src/basic/util.c b/src/basic/util.c
index b52a5db31b..687de40993 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -34,6 +34,7 @@
#include <unistd.h>
#include "alloc-util.h"
+#include "btrfs-util.h"
#include "build.h"
#include "cgroup-util.h"
#include "def.h"
@@ -219,7 +220,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- parent_pid = getpid();
+ parent_pid = getpid_cached();
/* First we temporarily block all signals, so that the new
* child has them blocked initially. This way, we can be sure
@@ -377,7 +378,7 @@ int on_ac_power(void) {
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (device < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
+ if (IN_SET(errno, ENOENT, ENOTDIR))
continue;
return -errno;
@@ -719,3 +720,133 @@ int version(void) {
SYSTEMD_FEATURES);
return 0;
}
+
+int get_block_device(const char *path, dev_t *dev) {
+ struct stat st;
+ struct statfs sfs;
+
+ assert(path);
+ assert(dev);
+
+ /* Get's the block device directly backing a file system. If
+ * the block device is encrypted, returns the device mapper
+ * block device. */
+
+ if (lstat(path, &st))
+ return -errno;
+
+ if (major(st.st_dev) != 0) {
+ *dev = st.st_dev;
+ return 1;
+ }
+
+ if (statfs(path, &sfs) < 0)
+ return -errno;
+
+ if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
+ return btrfs_get_block_device(path, dev);
+
+ return 0;
+}
+
+int get_block_device_harder(const char *path, dev_t *dev) {
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_free_ char *p = NULL, *t = NULL;
+ struct dirent *de, *found = NULL;
+ const char *q;
+ unsigned maj, min;
+ dev_t dt;
+ int r;
+
+ assert(path);
+ assert(dev);
+
+ /* Gets the backing block device for a file system, and
+ * handles LUKS encrypted file systems, looking for its
+ * immediate parent, if there is one. */
+
+ r = get_block_device(path, &dt);
+ if (r <= 0)
+ return r;
+
+ if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
+ return -ENOMEM;
+
+ d = opendir(p);
+ if (!d) {
+ if (errno == ENOENT)
+ goto fallback;
+
+ return -errno;
+ }
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+
+ if (dot_or_dot_dot(de->d_name))
+ continue;
+
+ if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
+ continue;
+
+ if (found) {
+ _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
+
+ /* We found a device backed by multiple other devices. We don't really support automatic
+ * discovery on such setups, with the exception of dm-verity partitions. In this case there are
+ * two backing devices: the data partition and the hash partition. We are fine with such
+ * setups, however, only if both partitions are on the same physical device. Hence, let's
+ * verify this. */
+
+ u = strjoin(p, "/", de->d_name, "/../dev");
+ if (!u)
+ return -ENOMEM;
+
+ v = strjoin(p, "/", found->d_name, "/../dev");
+ if (!v)
+ return -ENOMEM;
+
+ r = read_one_line_file(u, &a);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to read %s: %m", u);
+ goto fallback;
+ }
+
+ r = read_one_line_file(v, &b);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to read %s: %m", v);
+ goto fallback;
+ }
+
+ /* Check if the parent device is the same. If not, then the two backing devices are on
+ * different physical devices, and we don't support that. */
+ if (!streq(a, b))
+ goto fallback;
+ }
+
+ found = de;
+ }
+
+ if (!found)
+ goto fallback;
+
+ q = strjoina(p, "/", found->d_name, "/dev");
+
+ r = read_one_line_file(q, &t);
+ if (r == -ENOENT)
+ goto fallback;
+ if (r < 0)
+ return r;
+
+ if (sscanf(t, "%u:%u", &maj, &min) != 2)
+ return -EINVAL;
+
+ if (maj == 0)
+ goto fallback;
+
+ *dev = makedev(maj, min);
+ return 1;
+
+fallback:
+ *dev = dt;
+ return 1;
+}
diff --git a/src/basic/util.h b/src/basic/util.h
index c7da6c39bf..b31dfd1c92 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -192,3 +192,6 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
int update_reboot_parameter_and_warn(const char *param);
int version(void);
+
+int get_block_device(const char *path, dev_t *dev);
+int get_block_device_harder(const char *path, dev_t *dev);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 6011744523..d8eeb54dbf 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -46,6 +46,7 @@ static int detect_vm_cpuid(void) {
} cpuid_vendor_table[] = {
{ "XenVMMXenVMM", VIRTUALIZATION_XEN },
{ "KVMKVMKVM", VIRTUALIZATION_KVM },
+ { "TCGTCGTCGTCG", VIRTUALIZATION_QEMU },
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMwareVMware", VIRTUALIZATION_VMWARE },
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
@@ -421,7 +422,7 @@ int detect_container(void) {
goto finish;
}
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
/* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
e = getenv("container");
diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c
index 8256899eda..e086376d7c 100644
--- a/src/basic/xattr-util.c
+++ b/src/basic/xattr-util.c
@@ -129,7 +129,7 @@ static int parse_crtime(le64_t le, usec_t *usec) {
assert(usec);
u = le64toh(le);
- if (u == 0 || u == (uint64_t) -1)
+ if (IN_SET(u, 0, (uint64_t) -1))
return -EIO;
*usec = (usec_t) u;
diff --git a/src/basic/xml.c b/src/basic/xml.c
index 1dbeac7324..a4337f4865 100644
--- a/src/basic/xml.c
+++ b/src/basic/xml.c
@@ -208,7 +208,7 @@ int xml_tokenize(const char **p, char **name, void **state, unsigned *line) {
if (*c == '=') {
c++;
- if (*c == '\'' || *c == '\"') {
+ if (IN_SET(*c, '\'', '\"')) {
/* Tag with a quoted value */
e = strchr(c+1, *c);
diff --git a/src/binfmt/Makefile b/src/binfmt/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/binfmt/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index eeef04fb1c..17af233ef8 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -182,7 +182,7 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
- r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (r < 0) {
log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
goto finish;
diff --git a/src/boot/Makefile b/src/boot/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/boot/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 233bc80292..85f3b42c48 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -539,12 +539,18 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
if (r < 0) {
- unlink(t);
- return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
+ (void) unlink(t);
+ return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
}
(void) copy_times(fd_from, fd_to);
+ r = fsync(fd_to);
+ if (r < 0) {
+ (void) unlink_noerrno(t);
+ return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
+ }
+
r = renameat(AT_FDCWD, t, AT_FDCWD, to);
if (r < 0) {
(void) unlink_noerrno(t);
@@ -912,7 +918,7 @@ static int install_loader_config(const char *esp_path) {
r = sd_id128_get_machine(&machine_id);
if (r < 0)
- return log_error_errno(r, "Failed to get machine did: %m");
+ return log_error_errno(r, "Failed to get machine id: %m");
p = strjoina(esp_path, "/loader/loader.conf");
@@ -932,7 +938,7 @@ static int install_loader_config(const char *esp_path) {
fprintf(f, "#timeout 3\n");
fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
- r = fflush_and_check(f);
+ r = fflush_sync_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write \"%s\": %m", p);
diff --git a/src/boot/efi/.gitignore b/src/boot/efi/.gitignore
deleted file mode 100644
index e193acbe12..0000000000
--- a/src/boot/efi/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/systemd_boot.so
-/stub.so
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 1e990b3825..12176f1fe0 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1650,15 +1650,14 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con
loaded_image->LoadOptions = options;
loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
-#ifdef SD_BOOT_LOG_TPM
+#if ENABLE_TPM
/* Try to log any options to the TPM, especially to catch manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err)) {
Print(L"Unable to add image options measurement: %r", err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return err;
+ uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
}
#endif
}
diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c
index b22d37b62d..324d1c8b9e 100644
--- a/src/boot/efi/measure.c
+++ b/src/boot/efi/measure.c
@@ -11,7 +11,7 @@
*
*/
-#ifdef SD_BOOT_LOG_TPM
+#if ENABLE_TPM
#include <efi.h>
#include <efilib.h>
diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build
index 5ef5b2d20b..eb0be02977 100644
--- a/src/boot/efi/meson.build
+++ b/src/boot/efi/meson.build
@@ -30,7 +30,7 @@ stub_sources = '''
stub.c
'''.split()
-if conf.get('ENABLE_EFI', false) and get_option('gnu-efi') != 'false'
+if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
efi_cc = get_option('efi-cc')
efi_ld = get_option('efi-ld')
@@ -64,7 +64,7 @@ if have_gnu_efi
efi_conf = configuration_data()
efi_conf.set_quoted('PACKAGE_VERSION', meson.project_version())
efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', EFI_MACHINE_TYPE_NAME)
- efi_conf.set('SD_BOOT_LOG_TPM', get_option('tpm'))
+ efi_conf.set10('ENABLE_TPM', get_option('tpm'))
efi_conf.set('SD_TPM_PCR', get_option('tpm-pcrindex'))
efi_config_h = configure_file(
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index bab5d46de9..e85ebf2c3f 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -87,15 +87,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
line[i] = options[i];
cmdline = line;
-#ifdef SD_BOOT_LOG_TPM
+#if ENABLE_TPM
/* Try to log any options to the TPM, especially manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err)) {
Print(L"Unable to add image options measurement: %r", err);
- uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
- return err;
+ uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
}
#endif
}
diff --git a/src/cgls/Makefile b/src/cgls/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/cgls/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/cgroups-agent/Makefile b/src/cgroups-agent/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/cgroups-agent/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/cgtop/Makefile b/src/cgtop/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/cgtop/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/core/.gitignore b/src/core/.gitignore
deleted file mode 100644
index 465b4fcc20..0000000000
--- a/src/core/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/macros.systemd
-/triggers.systemd
-/systemd.pc
diff --git a/src/core/Makefile b/src/core/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/core/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index a91906b626..6207f8185e 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -22,7 +22,7 @@
#include "audit-fd.h"
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#include <stdbool.h>
@@ -48,7 +48,7 @@ int get_audit_fd(void) {
audit_fd = audit_open();
if (audit_fd < 0) {
- if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
+ if (!IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT))
log_error_errno(errno, "Failed to connect to audit log: %m");
audit_fd = errno ? -errno : -EINVAL;
diff --git a/src/core/automount.c b/src/core/automount.c
index 0f72854ceb..9b0d1ca429 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -251,8 +251,7 @@ static void automount_set_state(Automount *a, AutomountState state) {
if (state != AUTOMOUNT_RUNNING)
automount_stop_expire(a);
- if (state != AUTOMOUNT_WAITING &&
- state != AUTOMOUNT_RUNNING)
+ if (!IN_SET(state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
unmount_autofs(a);
if (state != old_state)
@@ -325,6 +324,9 @@ static void automount_enter_dead(Automount *a, AutomountResult f) {
if (a->result == AUTOMOUNT_SUCCESS)
a->result = f;
+ if (a->result != AUTOMOUNT_SUCCESS)
+ log_unit_warning(UNIT(a), "Failed with result '%s'.", automount_result_to_string(a->result));
+
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
}
@@ -529,7 +531,6 @@ static void automount_trigger_notify(Unit *u, Unit *other) {
if (IN_SET(MOUNT(other)->state,
MOUNT_MOUNTING, MOUNT_MOUNTING_DONE,
MOUNT_MOUNTED, MOUNT_REMOUNTING,
- MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
MOUNT_FAILED)) {
@@ -543,7 +544,6 @@ static void automount_trigger_notify(Unit *u, Unit *other) {
/* The mount is in some unhappy state now, let's unfreeze any waiting clients */
if (IN_SET(MOUNT(other)->state,
MOUNT_DEAD, MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
MOUNT_FAILED)) {
@@ -590,7 +590,7 @@ static void automount_enter_waiting(Automount *a) {
}
xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
- xsprintf(name, "systemd-"PID_FMT, getpid());
+ xsprintf(name, "systemd-"PID_FMT, getpid_cached());
if (mount(name, a->where, "autofs", 0, options) < 0) {
r = -errno;
goto fail;
@@ -803,7 +803,7 @@ static int automount_start(Unit *u) {
int r;
assert(a);
- assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
+ assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED));
if (path_is_mount_point(a->where, NULL, 0) > 0) {
log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
@@ -835,7 +835,7 @@ static int automount_stop(Unit *u) {
Automount *a = AUTOMOUNT(u);
assert(a);
- assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
+ assert(IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING));
automount_enter_dead(a, AUTOMOUNT_SUCCESS);
return 1;
diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c
new file mode 100644
index 0000000000..909c1c8253
--- /dev/null
+++ b/src/core/bpf-firewall.c
@@ -0,0 +1,680 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/libbpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "bpf-firewall.h"
+#include "bpf-program.h"
+#include "fd-util.h"
+#include "ip-address-access.h"
+#include "unit.h"
+
+enum {
+ MAP_KEY_PACKETS,
+ MAP_KEY_BYTES,
+};
+
+enum {
+ ACCESS_ALLOWED = 1,
+ ACCESS_DENIED = 2,
+};
+
+/* Compile instructions for one list of addresses, one direction and one specific verdict on matches. */
+
+static int add_lookup_instructions(
+ BPFProgram *p,
+ int map_fd,
+ int protocol,
+ bool is_ingress,
+ int verdict) {
+
+ int r, addr_offset, addr_size;
+
+ assert(p);
+ assert(map_fd >= 0);
+
+ switch (protocol) {
+
+ case ETH_P_IP:
+ addr_size = sizeof(uint32_t);
+ addr_offset = is_ingress ?
+ offsetof(struct iphdr, saddr) :
+ offsetof(struct iphdr, daddr);
+ break;
+
+ case ETH_P_IPV6:
+ addr_size = 4 * sizeof(uint32_t);
+ addr_offset = is_ingress ?
+ offsetof(struct ip6_hdr, ip6_src.s6_addr) :
+ offsetof(struct ip6_hdr, ip6_dst.s6_addr);
+ break;
+
+ default:
+ return -EAFNOSUPPORT;
+ }
+
+ do {
+ /* Compare IPv4 with one word instruction (32bit) */
+ struct bpf_insn insn[] = {
+ /* If skb->protocol != ETH_P_IP, skip this whole block. The offset will be set later. */
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_7, htobe16(protocol), 0),
+
+ /*
+ * Call into BPF_FUNC_skb_load_bytes to load the dst/src IP address
+ *
+ * R1: Pointer to the skb
+ * R2: Data offset
+ * R3: Destination buffer on the stack (r10 - 4)
+ * R4: Number of bytes to read (4)
+ */
+
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
+ BPF_MOV32_IMM(BPF_REG_2, addr_offset),
+
+ BPF_MOV64_REG(BPF_REG_3, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -addr_size),
+
+ BPF_MOV32_IMM(BPF_REG_4, addr_size),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_skb_load_bytes),
+
+ /*
+ * Call into BPF_FUNC_map_lookup_elem to see if the address matches any entry in the
+ * LPM trie map. For this to work, the prefixlen field of 'struct bpf_lpm_trie_key'
+ * has to be set to the maximum possible value.
+ *
+ * On success, the looked up value is stored in R0. For this application, the actual
+ * value doesn't matter, however; we just set the bit in @verdict in R8 if we found any
+ * matching value.
+ */
+
+ BPF_LD_MAP_FD(BPF_REG_1, map_fd),
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -addr_size - sizeof(uint32_t)),
+ BPF_ST_MEM(BPF_W, BPF_REG_2, 0, addr_size * 8),
+
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 1),
+ BPF_ALU32_IMM(BPF_OR, BPF_REG_8, verdict),
+ };
+
+ /* Jump label fixup */
+ insn[0].off = ELEMENTSOF(insn) - 1;
+
+ r = bpf_program_add_instructions(p, insn, ELEMENTSOF(insn));
+ if (r < 0)
+ return r;
+
+ } while (false);
+
+ return 0;
+}
+
+static int bpf_firewall_compile_bpf(
+ Unit *u,
+ bool is_ingress,
+ BPFProgram **ret) {
+
+ struct bpf_insn pre_insn[] = {
+ /*
+ * When the eBPF program is entered, R1 contains the address of the skb.
+ * However, R1-R5 are scratch registers that are not preserved when calling
+ * into kernel functions, so we need to save anything that's supposed to
+ * stay around to R6-R9. Save the skb to R6.
+ */
+ BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
+
+ /*
+ * Although we cannot access the skb data directly from eBPF programs used in this
+ * scenario, the kernel has prepared some fields for us to access through struct __sk_buff.
+ * Load the protocol (IPv4, IPv6) used by the packet in flight once and cache it in R7
+ * for later use.
+ */
+ BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, offsetof(struct __sk_buff, protocol)),
+
+ /*
+ * R8 is used to keep track of whether any address check has explicitly allowed or denied the packet
+ * through ACCESS_DENIED or ACCESS_ALLOWED bits. Reset them both to 0 in the beginning.
+ */
+ BPF_MOV32_IMM(BPF_REG_8, 0),
+ };
+
+ /*
+ * The access checkers compiled for the configured allowance and denial lists
+ * write to R8 at runtime. The following code prepares for an early exit that
+ * skip the accounting if the packet is denied.
+ *
+ * R0 = 1
+ * if (R8 == ACCESS_DENIED)
+ * R0 = 0
+ *
+ * This means that if both ACCESS_DENIED and ACCESS_ALLOWED are set, the packet
+ * is allowed to pass.
+ */
+ struct bpf_insn post_insn[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_8, ACCESS_DENIED, 1),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ };
+
+ _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+ int accounting_map_fd, r;
+ bool access_enabled;
+
+ assert(u);
+ assert(ret);
+
+ accounting_map_fd = is_ingress ?
+ u->ip_accounting_ingress_map_fd :
+ u->ip_accounting_egress_map_fd;
+
+ access_enabled =
+ u->ipv4_allow_map_fd >= 0 ||
+ u->ipv6_allow_map_fd >= 0 ||
+ u->ipv4_deny_map_fd >= 0 ||
+ u->ipv6_deny_map_fd >= 0;
+
+ if (accounting_map_fd < 0 && !access_enabled) {
+ *ret = NULL;
+ return 0;
+ }
+
+ r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &p);
+ if (r < 0)
+ return r;
+
+ r = bpf_program_add_instructions(p, pre_insn, ELEMENTSOF(pre_insn));
+ if (r < 0)
+ return r;
+
+ if (access_enabled) {
+ /*
+ * The simple rule this function translates into eBPF instructions is:
+ *
+ * - Access will be granted when an address matches an entry in @list_allow
+ * - Otherwise, access will be denied when an address matches an entry in @list_deny
+ * - Otherwise, access will be granted
+ */
+
+ if (u->ipv4_deny_map_fd >= 0) {
+ r = add_lookup_instructions(p, u->ipv4_deny_map_fd, ETH_P_IP, is_ingress, ACCESS_DENIED);
+ if (r < 0)
+ return r;
+ }
+
+ if (u->ipv6_deny_map_fd >= 0) {
+ r = add_lookup_instructions(p, u->ipv6_deny_map_fd, ETH_P_IPV6, is_ingress, ACCESS_DENIED);
+ if (r < 0)
+ return r;
+ }
+
+ if (u->ipv4_allow_map_fd >= 0) {
+ r = add_lookup_instructions(p, u->ipv4_allow_map_fd, ETH_P_IP, is_ingress, ACCESS_ALLOWED);
+ if (r < 0)
+ return r;
+ }
+
+ if (u->ipv6_allow_map_fd >= 0) {
+ r = add_lookup_instructions(p, u->ipv6_allow_map_fd, ETH_P_IPV6, is_ingress, ACCESS_ALLOWED);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ r = bpf_program_add_instructions(p, post_insn, ELEMENTSOF(post_insn));
+ if (r < 0)
+ return r;
+
+ if (accounting_map_fd >= 0) {
+ struct bpf_insn insn[] = {
+ /*
+ * If R0 == 0, the packet will be denied; skip the accounting instructions in this case.
+ * The jump label will be fixed up later.
+ */
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 0),
+
+ /* Count packets */
+ BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 0 */
+ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
+ BPF_LD_MAP_FD(BPF_REG_1, accounting_map_fd), /* load map fd to r1 */
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+ BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */
+ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
+
+ /* Count bytes */
+ BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */
+ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
+ BPF_LD_MAP_FD(BPF_REG_1, accounting_map_fd),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
+ BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */
+ BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
+
+ /* Allow the packet to pass */
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ };
+
+ /* Jump label fixup */
+ insn[0].off = ELEMENTSOF(insn) - 1;
+
+ r = bpf_program_add_instructions(p, insn, ELEMENTSOF(insn));
+ if (r < 0)
+ return r;
+ }
+
+ do {
+ /*
+ * Exit from the eBPF program, R0 contains the verdict.
+ * 0 means the packet is denied, 1 means the packet may pass.
+ */
+ struct bpf_insn insn[] = {
+ BPF_EXIT_INSN()
+ };
+
+ r = bpf_program_add_instructions(p, insn, ELEMENTSOF(insn));
+ if (r < 0)
+ return r;
+ } while (false);
+
+ *ret = p;
+ p = NULL;
+
+ return 0;
+}
+
+static int bpf_firewall_count_access_items(IPAddressAccessItem *list, size_t *n_ipv4, size_t *n_ipv6) {
+ IPAddressAccessItem *a;
+
+ assert(n_ipv4);
+ assert(n_ipv6);
+
+ LIST_FOREACH(items, a, list) {
+ switch (a->family) {
+
+ case AF_INET:
+ (*n_ipv4)++;
+ break;
+
+ case AF_INET6:
+ (*n_ipv6)++;
+ break;
+
+ default:
+ return -EAFNOSUPPORT;
+ }
+ }
+
+ return 0;
+}
+
+static int bpf_firewall_add_access_items(
+ IPAddressAccessItem *list,
+ int ipv4_map_fd,
+ int ipv6_map_fd,
+ int verdict) {
+
+ struct bpf_lpm_trie_key *key_ipv4, *key_ipv6;
+ uint64_t value = verdict;
+ IPAddressAccessItem *a;
+ int r;
+
+ key_ipv4 = alloca0(offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t));
+ key_ipv6 = alloca0(offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t) * 4);
+
+ LIST_FOREACH(items, a, list) {
+ switch (a->family) {
+
+ case AF_INET:
+ key_ipv4->prefixlen = a->prefixlen;
+ memcpy(key_ipv4->data, &a->address, sizeof(uint32_t));
+
+ r = bpf_map_update_element(ipv4_map_fd, key_ipv4, &value);
+ if (r < 0)
+ return r;
+
+ break;
+
+ case AF_INET6:
+ key_ipv6->prefixlen = a->prefixlen;
+ memcpy(key_ipv6->data, &a->address, 4 * sizeof(uint32_t));
+
+ r = bpf_map_update_element(ipv6_map_fd, key_ipv6, &value);
+ if (r < 0)
+ return r;
+
+ break;
+
+ default:
+ return -EAFNOSUPPORT;
+ }
+ }
+
+ return 0;
+}
+
+static int bpf_firewall_prepare_access_maps(
+ Unit *u,
+ int verdict,
+ int *ret_ipv4_map_fd,
+ int *ret_ipv6_map_fd) {
+
+ _cleanup_close_ int ipv4_map_fd = -1, ipv6_map_fd = -1;
+ size_t n_ipv4 = 0, n_ipv6 = 0;
+ Unit *p;
+ int r;
+
+ assert(ret_ipv4_map_fd);
+ assert(ret_ipv6_map_fd);
+
+ for (p = u; p; p = UNIT_DEREF(p->slice)) {
+ CGroupContext *cc;
+
+ cc = unit_get_cgroup_context(p);
+ if (!cc)
+ continue;
+
+ bpf_firewall_count_access_items(verdict == ACCESS_ALLOWED ? cc->ip_address_allow : cc->ip_address_deny, &n_ipv4, &n_ipv6);
+ }
+
+ if (n_ipv4 > 0) {
+ ipv4_map_fd = bpf_map_new(
+ BPF_MAP_TYPE_LPM_TRIE,
+ offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t),
+ sizeof(uint64_t),
+ n_ipv4,
+ BPF_F_NO_PREALLOC);
+ if (ipv4_map_fd < 0)
+ return ipv4_map_fd;
+ }
+
+ if (n_ipv6 > 0) {
+ ipv6_map_fd = bpf_map_new(
+ BPF_MAP_TYPE_LPM_TRIE,
+ offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t)*4,
+ sizeof(uint64_t),
+ n_ipv6,
+ BPF_F_NO_PREALLOC);
+ if (ipv6_map_fd < 0)
+ return ipv6_map_fd;
+ }
+
+ for (p = u; p; p = UNIT_DEREF(p->slice)) {
+ CGroupContext *cc;
+
+ cc = unit_get_cgroup_context(p);
+ if (!cc)
+ continue;
+
+ r = bpf_firewall_add_access_items(verdict == ACCESS_ALLOWED ? cc->ip_address_allow : cc->ip_address_deny,
+ ipv4_map_fd, ipv6_map_fd, verdict);
+ if (r < 0)
+ return r;
+ }
+
+ *ret_ipv4_map_fd = ipv4_map_fd;
+ *ret_ipv6_map_fd = ipv6_map_fd;
+
+ ipv4_map_fd = ipv6_map_fd = -1;
+ return 0;
+}
+
+static int bpf_firewall_prepare_accounting_maps(bool enabled, int *fd_ingress, int *fd_egress) {
+ int r;
+
+ assert(fd_ingress);
+ assert(fd_egress);
+
+ if (enabled) {
+ if (*fd_ingress < 0) {
+ r = bpf_map_new(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
+ if (r < 0)
+ return r;
+
+ *fd_ingress = r;
+ }
+
+ if (*fd_egress < 0) {
+
+ r = bpf_map_new(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
+ if (r < 0)
+ return r;
+
+ *fd_egress = r;
+ }
+ } else {
+ *fd_ingress = safe_close(*fd_ingress);
+ *fd_egress = safe_close(*fd_egress);
+ }
+
+ return 0;
+}
+
+int bpf_firewall_compile(Unit *u) {
+ CGroupContext *cc;
+ int r;
+
+ assert(u);
+
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_debug("BPF firewalling not supported on this systemd, proceeding without.");
+ return -EOPNOTSUPP;
+ }
+
+ /* Note that when we compile a new firewall we first flush out the access maps and the BPF programs themselves,
+ * but we reuse the the accounting maps. That way the firewall in effect always maps to the actual
+ * configuration, but we don't flush out the accounting unnecessarily */
+
+ u->ip_bpf_ingress = bpf_program_unref(u->ip_bpf_ingress);
+ u->ip_bpf_egress = bpf_program_unref(u->ip_bpf_egress);
+
+ u->ipv4_allow_map_fd = safe_close(u->ipv4_allow_map_fd);
+ u->ipv4_deny_map_fd = safe_close(u->ipv4_deny_map_fd);
+
+ u->ipv6_allow_map_fd = safe_close(u->ipv6_allow_map_fd);
+ u->ipv6_deny_map_fd = safe_close(u->ipv6_deny_map_fd);
+
+ cc = unit_get_cgroup_context(u);
+ if (!cc)
+ return -EINVAL;
+
+ r = bpf_firewall_prepare_access_maps(u, ACCESS_ALLOWED, &u->ipv4_allow_map_fd, &u->ipv6_allow_map_fd);
+ if (r < 0)
+ return log_error_errno(r, "Preparation of eBPF allow maps failed: %m");
+
+ r = bpf_firewall_prepare_access_maps(u, ACCESS_DENIED, &u->ipv4_deny_map_fd, &u->ipv6_deny_map_fd);
+ if (r < 0)
+ return log_error_errno(r, "Preparation of eBPF deny maps failed: %m");
+
+ r = bpf_firewall_prepare_accounting_maps(cc->ip_accounting, &u->ip_accounting_ingress_map_fd, &u->ip_accounting_egress_map_fd);
+ if (r < 0)
+ return log_error_errno(r, "Preparation of eBPF accounting maps failed: %m");
+
+ r = bpf_firewall_compile_bpf(u, true, &u->ip_bpf_ingress);
+ if (r < 0)
+ return log_error_errno(r, "Compilation for ingress BPF program failed: %m");
+
+ r = bpf_firewall_compile_bpf(u, false, &u->ip_bpf_egress);
+ if (r < 0)
+ return log_error_errno(r, "Compilation for egress BPF program failed: %m");
+
+ return 0;
+}
+
+int bpf_firewall_install(Unit *u) {
+ _cleanup_free_ char *path = NULL;
+ CGroupContext *cc;
+ int r;
+
+ assert(u);
+
+ if (!u->cgroup_path)
+ return -EINVAL;
+
+ cc = unit_get_cgroup_context(u);
+ if (!cc)
+ return -EINVAL;
+
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_debug("BPF firewalling not supported on this systemd, proceeding without.");
+ return -EOPNOTSUPP;
+ }
+
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine cgroup path: %m");
+
+ if (u->ip_bpf_egress) {
+ r = bpf_program_load_kernel(u->ip_bpf_egress, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Kernel upload of egress BPF program failed: %m");
+
+ r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, cc->delegate ? BPF_F_ALLOW_OVERRIDE : 0);
+ if (r < 0)
+ return log_error_errno(r, "Attaching egress BPF program to cgroup %s failed: %m", path);
+ } else {
+ r = bpf_program_cgroup_detach(BPF_CGROUP_INET_EGRESS, path);
+ if (r < 0)
+ return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
+ "Detaching egress BPF program from cgroup failed: %m");
+ }
+
+ if (u->ip_bpf_ingress) {
+ r = bpf_program_load_kernel(u->ip_bpf_ingress, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Kernel upload of ingress BPF program failed: %m");
+
+ r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, cc->delegate ? BPF_F_ALLOW_OVERRIDE : 0);
+ if (r < 0)
+ return log_error_errno(r, "Attaching ingress BPF program to cgroup %s failed: %m", path);
+ } else {
+ r = bpf_program_cgroup_detach(BPF_CGROUP_INET_INGRESS, path);
+ if (r < 0)
+ return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
+ "Detaching ingress BPF program from cgroup failed: %m");
+ }
+
+ return 0;
+}
+
+int bpf_firewall_read_accounting(int map_fd, uint64_t *ret_bytes, uint64_t *ret_packets) {
+ uint64_t key, packets;
+ int r;
+
+ if (map_fd < 0)
+ return -EBADF;
+
+ if (ret_packets) {
+ key = MAP_KEY_PACKETS;
+ r = bpf_map_lookup_element(map_fd, &key, &packets);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_bytes) {
+ key = MAP_KEY_BYTES;
+ r = bpf_map_lookup_element(map_fd, &key, ret_bytes);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_packets)
+ *ret_packets = packets;
+
+ return 0;
+}
+
+int bpf_firewall_reset_accounting(int map_fd) {
+ uint64_t key, value = 0;
+ int r;
+
+ if (map_fd < 0)
+ return -EBADF;
+
+ key = MAP_KEY_PACKETS;
+ r = bpf_map_update_element(map_fd, &key, &value);
+ if (r < 0)
+ return r;
+
+ key = MAP_KEY_BYTES;
+ return bpf_map_update_element(map_fd, &key, &value);
+}
+
+
+int bpf_firewall_supported(void) {
+ static int supported = -1;
+ int fd, r;
+
+ /* Checks whether BPF firewalling is supported. For this, we check three things:
+ *
+ * a) whether we are privileged
+ * b) whether the unified hierarchy is being used
+ * c) the BPF implementation in the kernel supports BPF LPM TRIE maps, which we require
+ *
+ */
+
+ if (supported >= 0)
+ return supported;
+
+ if (geteuid() != 0)
+ return supported = false;
+
+ r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
+ if (r < 0)
+ return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m");
+ if (r == 0)
+ return supported = false;
+
+ fd = bpf_map_new(BPF_MAP_TYPE_LPM_TRIE,
+ offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint64_t),
+ sizeof(uint64_t),
+ 1,
+ BPF_F_NO_PREALLOC);
+ if (fd < 0) {
+ log_debug_errno(r, "Can't allocate BPF LPM TRIE map, BPF firewalling is not supported: %m");
+ return supported = false;
+ }
+
+ safe_close(fd);
+
+ return supported = true;
+}
diff --git a/src/core/bpf-firewall.h b/src/core/bpf-firewall.h
new file mode 100644
index 0000000000..870e314e0e
--- /dev/null
+++ b/src/core/bpf-firewall.h
@@ -0,0 +1,32 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 <inttypes.h>
+
+#include "unit.h"
+
+int bpf_firewall_supported(void);
+
+int bpf_firewall_compile(Unit *u);
+int bpf_firewall_install(Unit *u);
+
+int bpf_firewall_read_accounting(int map_fd, uint64_t *ret_bytes, uint64_t *ret_packets);
+int bpf_firewall_reset_accounting(int map_fd);
diff --git a/src/core/busname.h b/src/core/busname.h
deleted file mode 100644
index a8562db458..0000000000
--- a/src/core/busname.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#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/>.
-***/
-
-typedef struct BusName BusName;
-typedef struct BusNamePolicy BusNamePolicy;
-
-#include "unit.h"
-#include "bus-policy.h"
-
-typedef enum BusNameResult {
- BUSNAME_SUCCESS,
- BUSNAME_FAILURE_RESOURCES,
- BUSNAME_FAILURE_TIMEOUT,
- BUSNAME_FAILURE_EXIT_CODE,
- BUSNAME_FAILURE_SIGNAL,
- BUSNAME_FAILURE_CORE_DUMP,
- BUSNAME_FAILURE_START_LIMIT_HIT,
- BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
- _BUSNAME_RESULT_MAX,
- _BUSNAME_RESULT_INVALID = -1
-} BusNameResult;
-
-struct BusName {
- Unit meta;
-
- char *name;
- int starter_fd;
-
- bool activating;
- bool accept_fd;
-
- UnitRef service;
-
- BusNameState state, deserialized_state;
- BusNameResult result;
-
- usec_t timeout_usec;
-
- sd_event_source *starter_event_source;
- sd_event_source *timer_event_source;
-
- pid_t control_pid;
-
- LIST_HEAD(BusNamePolicy, policy);
- BusPolicyAccess policy_world;
-};
-
-extern const UnitVTable busname_vtable;
-
-const char* busname_result_to_string(BusNameResult i) _const_;
-BusNameResult busname_result_from_string(const char *s) _pure_;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index d95d236d75..4e74e7b3f1 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -21,6 +21,7 @@
#include <fnmatch.h>
#include "alloc-util.h"
+#include "bpf-firewall.h"
#include "cgroup-util.h"
#include "cgroup.h"
#include "fd-util.h"
@@ -30,9 +31,9 @@
#include "path-util.h"
#include "process-util.h"
#include "special.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
-#include "stdio-util.h"
#include "umask-util.h"
#include "smack-util.h"
@@ -143,6 +144,9 @@ void cgroup_context_done(CGroupContext *c) {
while (c->device_allow)
cgroup_context_free_device_allow(c, c->device_allow);
+
+ c->ip_address_allow = ip_address_access_free_all(c->ip_address_allow);
+ c->ip_address_deny = ip_address_access_free_all(c->ip_address_deny);
}
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
@@ -151,6 +155,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceWeight *w;
CGroupDeviceAllow *a;
+ IPAddressAccessItem *iaai;
char u[FORMAT_TIMESPAN_MAX];
assert(c);
@@ -164,6 +169,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sBlockIOAccounting=%s\n"
"%sMemoryAccounting=%s\n"
"%sTasksAccounting=%s\n"
+ "%sIPAccounting=%s\n"
"%sCPUWeight=%" PRIu64 "\n"
"%sStartupCPUWeight=%" PRIu64 "\n"
"%sCPUShares=%" PRIu64 "\n"
@@ -186,6 +192,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
prefix, yes_no(c->tasks_accounting),
+ prefix, yes_no(c->ip_accounting),
prefix, c->cpu_weight,
prefix, c->startup_cpu_weight,
prefix, c->cpu_shares,
@@ -255,6 +262,20 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
b->path,
format_bytes(buf, sizeof(buf), b->wbps));
}
+
+ LIST_FOREACH(items, iaai, c->ip_address_allow) {
+ _cleanup_free_ char *k = NULL;
+
+ (void) in_addr_to_string(iaai->family, &iaai->address, &k);
+ fprintf(f, "%sIPAddressAllow=%s/%u\n", prefix, strnull(k), iaai->prefixlen);
+ }
+
+ LIST_FOREACH(items, iaai, c->ip_address_deny) {
+ _cleanup_free_ char *k = NULL;
+
+ (void) in_addr_to_string(iaai->family, &iaai->address, &k);
+ fprintf(f, "%sIPAddressDeny=%s/%u\n", prefix, strnull(k), iaai->prefixlen);
+ }
}
static int lookup_block_device(const char *p, dev_t *dev) {
@@ -336,7 +357,7 @@ static int whitelist_major(const char *path, const char *name, char type, const
assert(path);
assert(acc);
- assert(type == 'b' || type == 'c');
+ assert(IN_SET(type, 'b', 'c'));
f = fopen("/proc/devices", "re");
if (!f)
@@ -647,7 +668,27 @@ static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_
"Failed to set %s: %m", file);
}
-static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
+static void cgroup_apply_firewall(Unit *u, CGroupContext *c) {
+ int r;
+
+ if (u->type == UNIT_SLICE) /* Skip this for slice units, they are inner cgroup nodes, and since bpf/cgroup is
+ * not recursive we don't ever touch the bpf on them */
+ return;
+
+ r = bpf_firewall_compile(u);
+ if (r < 0)
+ return;
+
+ (void) bpf_firewall_install(u);
+ return;
+}
+
+static void cgroup_context_apply(
+ Unit *u,
+ CGroupMask apply_mask,
+ bool apply_bpf,
+ ManagerState state) {
+
const char *path;
CGroupContext *c;
bool is_root;
@@ -661,7 +702,8 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
assert(c);
assert(path);
- if (mask == 0)
+ /* Nothing to do? Exit early! */
+ if (apply_mask == 0 && !apply_bpf)
return;
/* Some cgroup attributes are not supported on the root cgroup,
@@ -675,9 +717,11 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
* cgroup trees (assuming we are running in a container then),
* and missing cgroups, i.e. EROFS and ENOENT. */
- if ((mask & CGROUP_MASK_CPU) && !is_root) {
- bool has_weight = cgroup_context_has_cpu_weight(c);
- bool has_shares = cgroup_context_has_cpu_shares(c);
+ if ((apply_mask & CGROUP_MASK_CPU) && !is_root) {
+ bool has_weight, has_shares;
+
+ has_weight = cgroup_context_has_cpu_weight(c);
+ has_shares = cgroup_context_has_cpu_shares(c);
if (cg_all_unified() > 0) {
uint64_t weight;
@@ -714,7 +758,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
}
}
- if (mask & CGROUP_MASK_IO) {
+ if (apply_mask & CGROUP_MASK_IO) {
bool has_io = cgroup_context_has_io_config(c);
bool has_blockio = cgroup_context_has_blockio_config(c);
@@ -791,7 +835,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
}
}
- if (mask & CGROUP_MASK_BLKIO) {
+ if (apply_mask & CGROUP_MASK_BLKIO) {
bool has_io = cgroup_context_has_io_config(c);
bool has_blockio = cgroup_context_has_blockio_config(c);
@@ -858,7 +902,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
}
}
- if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
+ if ((apply_mask & CGROUP_MASK_MEMORY) && !is_root) {
if (cg_all_unified() > 0) {
uint64_t max, swap_max = CGROUP_LIMIT_MAX;
@@ -898,7 +942,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
}
}
- if ((mask & CGROUP_MASK_DEVICES) && !is_root) {
+ if ((apply_mask & CGROUP_MASK_DEVICES) && !is_root) {
CGroupDeviceAllow *a;
/* Changing the devices list of a populated cgroup
@@ -933,8 +977,6 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
whitelist_device(path, x, y);
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) {
@@ -953,7 +995,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
acc[k++] = 0;
- if (startswith(a->path, "/dev/"))
+ if (path_startswith(a->path, "/dev/"))
whitelist_device(path, a->path, acc);
else if ((val = startswith(a->path, "block-")))
whitelist_major(path, val, 'b', acc);
@@ -964,7 +1006,7 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
}
}
- if ((mask & CGROUP_MASK_PIDS) && !is_root) {
+ if ((apply_mask & CGROUP_MASK_PIDS) && !is_root) {
if (c->tasks_max != CGROUP_LIMIT_MAX) {
char buf[DECIMAL_STR_MAX(uint64_t) + 2];
@@ -978,6 +1020,9 @@ static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set pids.max: %m");
}
+
+ if (apply_bpf)
+ cgroup_apply_firewall(u, c);
}
CGroupMask cgroup_context_get_mask(CGroupContext *c) {
@@ -1124,6 +1169,39 @@ CGroupMask unit_get_enable_mask(Unit *u) {
return mask;
}
+bool unit_get_needs_bpf(Unit *u) {
+ CGroupContext *c;
+ Unit *p;
+ assert(u);
+
+ /* We never attach BPF to slice units, as they are inner cgroup nodes and cgroup/BPF is not recursive at the
+ * moment. */
+ if (u->type == UNIT_SLICE)
+ return false;
+
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return false;
+
+ if (c->ip_accounting ||
+ c->ip_address_allow ||
+ c->ip_address_deny)
+ return true;
+
+ /* If any parent slice has an IP access list defined, it applies too */
+ for (p = UNIT_DEREF(u->slice); p; p = UNIT_DEREF(p->slice)) {
+ c = unit_get_cgroup_context(p);
+ if (!c)
+ return false;
+
+ if (c->ip_address_allow ||
+ c->ip_address_deny)
+ return true;
+ }
+
+ return false;
+}
+
/* Recurse from a unit up through its containing slices, propagating
* mask bits upward. A unit is also member of itself. */
void unit_update_cgroup_members_masks(Unit *u) {
@@ -1299,7 +1377,8 @@ int unit_watch_cgroup(Unit *u) {
static int unit_create_cgroup(
Unit *u,
CGroupMask target_mask,
- CGroupMask enable_mask) {
+ CGroupMask enable_mask,
+ bool needs_bpf) {
CGroupContext *c;
int r;
@@ -1341,6 +1420,7 @@ static int unit_create_cgroup(
u->cgroup_realized = true;
u->cgroup_realized_mask = target_mask;
u->cgroup_enabled_mask = enable_mask;
+ u->cgroup_bpf_state = needs_bpf ? UNIT_CGROUP_BPF_ON : UNIT_CGROUP_BPF_OFF;
if (u->type != UNIT_SLICE && !c->delegate) {
@@ -1390,10 +1470,19 @@ static void cgroup_xattr_apply(Unit *u) {
log_unit_warning_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path);
}
-static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
+static bool unit_has_mask_realized(
+ Unit *u,
+ CGroupMask target_mask,
+ CGroupMask enable_mask,
+ bool needs_bpf) {
+
assert(u);
- return u->cgroup_realized && u->cgroup_realized_mask == target_mask && u->cgroup_enabled_mask == enable_mask;
+ return u->cgroup_realized &&
+ u->cgroup_realized_mask == target_mask &&
+ u->cgroup_enabled_mask == enable_mask &&
+ ((needs_bpf && u->cgroup_bpf_state == UNIT_CGROUP_BPF_ON) ||
+ (!needs_bpf && u->cgroup_bpf_state == UNIT_CGROUP_BPF_OFF));
}
/* Check if necessary controllers and attributes for a unit are in place.
@@ -1404,21 +1493,28 @@ static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask e
* Returns 0 on success and < 0 on failure. */
static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
CGroupMask target_mask, enable_mask;
+ bool needs_bpf, apply_bpf;
int r;
assert(u);
- if (u->in_cgroup_queue) {
- LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
- u->in_cgroup_queue = false;
+ if (u->in_cgroup_realize_queue) {
+ LIST_REMOVE(cgroup_realize_queue, u->manager->cgroup_realize_queue, u);
+ u->in_cgroup_realize_queue = false;
}
target_mask = unit_get_target_mask(u);
enable_mask = unit_get_enable_mask(u);
+ needs_bpf = unit_get_needs_bpf(u);
- if (unit_has_mask_realized(u, target_mask, enable_mask))
+ if (unit_has_mask_realized(u, target_mask, enable_mask, needs_bpf))
return 0;
+ /* Make sure we apply the BPF filters either when one is configured, or if none is configured but previously
+ * the state was anything but off. This way, if a unit with a BPF filter applied is reconfigured to lose it
+ * this will trickle down properly to cgroupfs. */
+ apply_bpf = needs_bpf || u->cgroup_bpf_state != UNIT_CGROUP_BPF_OFF;
+
/* First, realize parents */
if (UNIT_ISSET(u->slice)) {
r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
@@ -1427,36 +1523,39 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
/* And then do the real work */
- r = unit_create_cgroup(u, target_mask, enable_mask);
+ r = unit_create_cgroup(u, target_mask, enable_mask, needs_bpf);
if (r < 0)
return r;
/* Finally, apply the necessary attributes. */
- cgroup_context_apply(u, target_mask, state);
+ cgroup_context_apply(u, target_mask, apply_bpf, state);
cgroup_xattr_apply(u);
return 0;
}
-static void unit_add_to_cgroup_queue(Unit *u) {
+static void unit_add_to_cgroup_realize_queue(Unit *u) {
+ assert(u);
- if (u->in_cgroup_queue)
+ if (u->in_cgroup_realize_queue)
return;
- LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
- u->in_cgroup_queue = true;
+ LIST_PREPEND(cgroup_realize_queue, u->manager->cgroup_realize_queue, u);
+ u->in_cgroup_realize_queue = true;
}
-unsigned manager_dispatch_cgroup_queue(Manager *m) {
+unsigned manager_dispatch_cgroup_realize_queue(Manager *m) {
ManagerState state;
unsigned n = 0;
Unit *i;
int r;
+ assert(m);
+
state = manager_state(m);
- while ((i = m->cgroup_queue)) {
- assert(i->in_cgroup_queue);
+ while ((i = m->cgroup_realize_queue)) {
+ assert(i->in_cgroup_realize_queue);
r = unit_realize_cgroup_now(i, state);
if (r < 0)
@@ -1468,7 +1567,7 @@ unsigned manager_dispatch_cgroup_queue(Manager *m) {
return n;
}
-static void unit_queue_siblings(Unit *u) {
+static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) {
Unit *slice;
/* This adds the siblings of the specified unit and the
@@ -1496,10 +1595,13 @@ static void unit_queue_siblings(Unit *u) {
/* If the unit doesn't need any new controllers
* and has current ones realized, it doesn't need
* any changes. */
- if (unit_has_mask_realized(m, unit_get_target_mask(m), unit_get_enable_mask(m)))
+ if (unit_has_mask_realized(m,
+ unit_get_target_mask(m),
+ unit_get_enable_mask(m),
+ unit_get_needs_bpf(m)))
continue;
- unit_add_to_cgroup_queue(m);
+ unit_add_to_cgroup_realize_queue(m);
}
u = slice;
@@ -1524,7 +1626,7 @@ int unit_realize_cgroup(Unit *u) {
* iteration. */
/* Add all sibling slices to the cgroup queue. */
- unit_queue_siblings(u);
+ unit_add_siblings_to_cgroup_realize_queue(u);
/* And realize this one now (and apply the values) */
return unit_realize_cgroup_now(u, manager_state(u->manager));
@@ -1595,7 +1697,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
if (r < 0)
return r;
- mypid = getpid();
+ mypid = getpid_cached();
while (cg_read_pid(f, &npid) > 0) {
pid_t ppid;
@@ -1694,17 +1796,28 @@ int unit_watch_all_pids(Unit *u) {
return unit_watch_pids_in_path(u, u->cgroup_path);
}
-int unit_notify_cgroup_empty(Unit *u) {
+static int on_cgroup_empty_event(sd_event_source *s, void *userdata) {
+ Manager *m = userdata;
+ Unit *u;
int r;
- assert(u);
+ assert(s);
+ assert(m);
- if (!u->cgroup_path)
+ u = m->cgroup_empty_queue;
+ if (!u)
return 0;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
- if (r <= 0)
- return r;
+ assert(u->in_cgroup_empty_queue);
+ u->in_cgroup_empty_queue = false;
+ LIST_REMOVE(cgroup_empty_queue, m->cgroup_empty_queue, u);
+
+ if (m->cgroup_empty_queue) {
+ /* More stuff queued, let's make sure we remain enabled */
+ r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
+ if (r < 0)
+ log_debug_errno(r, "Failed to reenable cgroup empty event source: %m");
+ }
unit_add_to_gc_queue(u);
@@ -1714,6 +1827,51 @@ int unit_notify_cgroup_empty(Unit *u) {
return 0;
}
+void unit_add_to_cgroup_empty_queue(Unit *u) {
+ int r;
+
+ assert(u);
+
+ /* Note that there are four different ways how cgroup empty events reach us:
+ *
+ * 1. On the unified hierarchy we get an inotify event on the cgroup
+ *
+ * 2. On the legacy hierarchy, when running in system mode, we get a datagram on the cgroup agent socket
+ *
+ * 3. On the legacy hierarchy, when running in user mode, we get a D-Bus signal on the system bus
+ *
+ * 4. On the legacy hierarchy, in service units we start watching all processes of the cgroup for SIGCHLD as
+ * soon as we get one SIGCHLD, to deal with unreliable cgroup notifications.
+ *
+ * Regardless which way we got the notification, we'll verify it here, and then add it to a separate
+ * queue. This queue will be dispatched at a lower priority than the SIGCHLD handler, so that we always use
+ * SIGCHLD if we can get it first, and only use the cgroup empty notifications if there's no SIGCHLD pending
+ * (which might happen if the cgroup doesn't contain processes that are our own child, which is typically the
+ * case for scope units). */
+
+ if (u->in_cgroup_empty_queue)
+ return;
+
+ /* Let's verify that the cgroup is really empty */
+ if (!u->cgroup_path)
+ return;
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
+ if (r < 0) {
+ log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", u->cgroup_path);
+ return;
+ }
+ if (r == 0)
+ return;
+
+ LIST_PREPEND(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
+ u->in_cgroup_empty_queue = true;
+
+ /* Trigger the defer event */
+ r = sd_event_source_set_enabled(u->manager->cgroup_empty_event_source, SD_EVENT_ONESHOT);
+ if (r < 0)
+ log_debug_errno(r, "Failed to enable cgroup empty event source: %m");
+}
+
static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
Manager *m = userdata;
@@ -1728,7 +1886,7 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents,
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
return 0;
return log_error_errno(errno, "Failed to read control group inotify events: %m");
@@ -1753,13 +1911,14 @@ static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents,
* this here safely. */
continue;
- (void) unit_notify_cgroup_empty(u);
+ unit_add_to_cgroup_empty_queue(u);
}
}
}
int manager_setup_cgroup(Manager *m) {
_cleanup_free_ char *path = NULL;
+ const char *scope_path;
CGroupController c;
int r, all_unified;
char *e;
@@ -1825,79 +1984,85 @@ int manager_setup_cgroup(Manager *m) {
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER_LEGACY ". File system hierarchy is at %s.", path);
}
- if (!m->test_run) {
- const char *scope_path;
+ /* 3. Allocate cgroup empty defer event source */
+ m->cgroup_empty_event_source = sd_event_source_unref(m->cgroup_empty_event_source);
+ r = sd_event_add_defer(m->event, &m->cgroup_empty_event_source, on_cgroup_empty_event, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create cgroup empty event source: %m");
- /* 3. Install agent */
- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0) {
+ r = sd_event_source_set_priority(m->cgroup_empty_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of cgroup empty event source: %m");
- /* In the unified hierarchy we can get
- * cgroup empty notifications via inotify. */
+ r = sd_event_source_set_enabled(m->cgroup_empty_event_source, SD_EVENT_OFF);
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable cgroup empty event source: %m");
- m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
- safe_close(m->cgroup_inotify_fd);
+ (void) sd_event_source_set_description(m->cgroup_empty_event_source, "cgroup-empty");
- m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->cgroup_inotify_fd < 0)
- return log_error_errno(errno, "Failed to create control group inotify object: %m");
+ /* 4. Install notifier inotify object, or agent */
+ if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0) {
- r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
- if (r < 0)
- return log_error_errno(r, "Failed to watch control group inotify object: %m");
+ /* In the unified hierarchy we can get cgroup empty notifications via inotify. */
- /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
- * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of inotify event source: %m");
+ m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
+ safe_close(m->cgroup_inotify_fd);
- (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
+ m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if (m->cgroup_inotify_fd < 0)
+ return log_error_errno(errno, "Failed to create control group inotify object: %m");
- } else if (MANAGER_IS_SYSTEM(m)) {
+ r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch control group inotify object: %m");
- /* On the legacy hierarchy we only get
- * notifications via cgroup agents. (Which
- * isn't really reliable, since it does not
- * generate events when control groups with
- * children run empty. */
+ /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
+ * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+ r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-4);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of inotify event source: %m");
- r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
- if (r < 0)
- log_warning_errno(r, "Failed to install release agent, ignoring: %m");
- else if (r > 0)
- log_debug("Installed release agent.");
- else if (r == 0)
- log_debug("Release agent already installed.");
- }
+ (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
- /* 4. Make sure we are in the special "init.scope" unit in the root slice. */
- scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
+ } else if (MANAGER_IS_SYSTEM(m) && m->test_run_flags == 0) {
+
+ /* On the legacy hierarchy we only get notifications via cgroup agents. (Which isn't really reliable,
+ * since it does not generate events when control groups with children run empty. */
- /* also, move all other userspace processes remaining
- * in the root cgroup into that scope. */
- r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
+ r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
if (r < 0)
- log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
+ log_warning_errno(r, "Failed to install release agent, ignoring: %m");
+ else if (r > 0)
+ log_debug("Installed release agent.");
+ else if (r == 0)
+ log_debug("Release agent already installed.");
+ }
- /* 5. And pin it, so that it cannot be unmounted */
- safe_close(m->pin_cgroupfs_fd);
- m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
- if (m->pin_cgroupfs_fd < 0)
- return log_error_errno(errno, "Failed to open pin file: %m");
+ /* 5. Make sure we are in the special "init.scope" unit in the root slice. */
+ scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
+ r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
- /* 6. Always enable hierarchical support if it exists... */
- if (!all_unified)
- (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
- }
+ /* Also, move all other userspace processes remaining in the root cgroup into that scope. */
+ r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
+ if (r < 0)
+ log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
+
+ /* 6. And pin it, so that it cannot be unmounted */
+ safe_close(m->pin_cgroupfs_fd);
+ m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
+ if (m->pin_cgroupfs_fd < 0)
+ return log_error_errno(errno, "Failed to open pin file: %m");
+
+ /* 7. Always enable hierarchical support if it exists... */
+ if (!all_unified && m->test_run_flags == 0)
+ (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
- /* 7. Figure out which controllers are supported */
+ /* 8. Figure out which controllers are supported, and log about it */
r = cg_mask_supported(&m->cgroup_supported);
if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m");
-
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & CGROUP_CONTROLLER_TO_MASK(c)));
@@ -1912,6 +2077,8 @@ void manager_shutdown_cgroup(Manager *m, bool delete) {
if (delete && m->cgroup_root)
(void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
+ m->cgroup_empty_event_source = sd_event_source_unref(m->cgroup_empty_event_source);
+
m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
@@ -1993,13 +2160,17 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
assert(m);
assert(cgroup);
+ /* Called on the legacy hierarchy whenever we get an explicit cgroup notification from the cgroup agent process
+ * or from the --system instance */
+
log_debug("Got cgroup empty notification for: %s", cgroup);
u = manager_get_unit_by_cgroup(m, cgroup);
if (!u)
return 0;
- return unit_notify_cgroup_empty(u);
+ unit_add_to_cgroup_empty_queue(u);
+ return 1;
}
int unit_get_memory_current(Unit *u, uint64_t *ret) {
@@ -2009,6 +2180,9 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) {
assert(u);
assert(ret);
+ if (!UNIT_CGROUP_BOOL(u, memory_accounting))
+ return -ENODATA;
+
if (!u->cgroup_path)
return -ENODATA;
@@ -2037,6 +2211,9 @@ int unit_get_tasks_current(Unit *u, uint64_t *ret) {
assert(u);
assert(ret);
+ if (!UNIT_CGROUP_BOOL(u, tasks_accounting))
+ return -ENODATA;
+
if (!u->cgroup_path)
return -ENODATA;
@@ -2112,6 +2289,9 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
* started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply
* call this function with a NULL return value. */
+ if (!UNIT_CGROUP_BOOL(u, cpu_accounting))
+ return -ENODATA;
+
r = unit_get_cpu_usage_raw(u, &ns);
if (r == -ENODATA && u->cpu_usage_last != NSEC_INFINITY) {
/* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our
@@ -2136,7 +2316,53 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
return 0;
}
-int unit_reset_cpu_usage(Unit *u) {
+int unit_get_ip_accounting(
+ Unit *u,
+ CGroupIPAccountingMetric metric,
+ uint64_t *ret) {
+
+ uint64_t value;
+ int fd, r;
+
+ assert(u);
+ assert(metric >= 0);
+ assert(metric < _CGROUP_IP_ACCOUNTING_METRIC_MAX);
+ assert(ret);
+
+ /* IP accounting is currently not recursive, and hence we refuse to return any data for slice nodes. Slices are
+ * inner cgroup nodes and hence have no processes directly attached, hence their counters would be zero
+ * anyway. And if we block this now we can later open this up, if the kernel learns recursive BPF cgroup
+ * filters. */
+ if (u->type == UNIT_SLICE)
+ return -ENODATA;
+
+ if (!UNIT_CGROUP_BOOL(u, ip_accounting))
+ return -ENODATA;
+
+ fd = IN_SET(metric, CGROUP_IP_INGRESS_BYTES, CGROUP_IP_INGRESS_PACKETS) ?
+ u->ip_accounting_ingress_map_fd :
+ u->ip_accounting_egress_map_fd;
+
+ if (fd < 0)
+ return -ENODATA;
+
+ if (IN_SET(metric, CGROUP_IP_INGRESS_BYTES, CGROUP_IP_EGRESS_BYTES))
+ r = bpf_firewall_read_accounting(fd, &value, NULL);
+ else
+ r = bpf_firewall_read_accounting(fd, NULL, &value);
+ if (r < 0)
+ return r;
+
+ /* Add in additional metrics from a previous runtime. Note that when reexecing/reloading the daemon we compile
+ * all BPF programs and maps anew, but serialize the old counters. When deserializing we store them in the
+ * ip_accounting_extra[] field, and add them in here transparently. */
+
+ *ret = value + u->ip_accounting_extra[metric];
+
+ return r;
+}
+
+int unit_reset_cpu_accounting(Unit *u) {
nsec_t ns;
int r;
@@ -2154,16 +2380,20 @@ int unit_reset_cpu_usage(Unit *u) {
return 0;
}
-bool unit_cgroup_delegate(Unit *u) {
- CGroupContext *c;
+int unit_reset_ip_accounting(Unit *u) {
+ int r = 0, q = 0;
assert(u);
- c = unit_get_cgroup_context(u);
- if (!c)
- return false;
+ if (u->ip_accounting_ingress_map_fd >= 0)
+ r = bpf_firewall_reset_accounting(u->ip_accounting_ingress_map_fd);
+
+ if (u->ip_accounting_egress_map_fd >= 0)
+ q = bpf_firewall_reset_accounting(u->ip_accounting_egress_map_fd);
- return c->delegate;
+ zero(u->ip_accounting_extra);
+
+ return r < 0 ? r : q;
}
void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
@@ -2179,11 +2409,44 @@ void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
if (m & (CGROUP_MASK_IO | CGROUP_MASK_BLKIO))
m |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
+ if (m & (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT))
+ m |= CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT;
+
if ((u->cgroup_realized_mask & m) == 0)
return;
u->cgroup_realized_mask &= ~m;
- unit_add_to_cgroup_queue(u);
+ unit_add_to_cgroup_realize_queue(u);
+}
+
+void unit_invalidate_cgroup_bpf(Unit *u) {
+ assert(u);
+
+ if (!UNIT_HAS_CGROUP_CONTEXT(u))
+ return;
+
+ if (u->cgroup_bpf_state == UNIT_CGROUP_BPF_INVALIDATED)
+ return;
+
+ u->cgroup_bpf_state = UNIT_CGROUP_BPF_INVALIDATED;
+ unit_add_to_cgroup_realize_queue(u);
+
+ /* If we are a slice unit, we also need to put compile a new BPF program for all our children, as the IP access
+ * list of our children includes our own. */
+ if (u->type == UNIT_SLICE) {
+ Unit *member;
+ Iterator i;
+
+ SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
+ if (member == u)
+ continue;
+
+ if (UNIT_DEREF(member->slice) != u)
+ continue;
+
+ unit_invalidate_cgroup_bpf(member);
+ }
+ }
}
void manager_invalidate_startup_units(Manager *m) {
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 4cd168f63e..65245fbc43 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -21,9 +21,10 @@
#include <stdbool.h>
+#include "cgroup-util.h"
+#include "ip-address-access.h"
#include "list.h"
#include "time-util.h"
-#include "cgroup-util.h"
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
@@ -87,6 +88,7 @@ struct CGroupContext {
bool blockio_accounting;
bool memory_accounting;
bool tasks_accounting;
+ bool ip_accounting;
/* For unified hierarchy */
uint64_t cpu_weight;
@@ -103,6 +105,9 @@ struct CGroupContext {
uint64_t memory_max;
uint64_t memory_swap_max;
+ LIST_HEAD(IPAddressAccessItem, ip_address_allow);
+ LIST_HEAD(IPAddressAccessItem, ip_address_deny);
+
/* For legacy hierarchies */
uint64_t cpu_shares;
uint64_t startup_cpu_shares;
@@ -123,6 +128,16 @@ struct CGroupContext {
bool delegate;
};
+/* Used when querying IP accounting data */
+typedef enum CGroupIPAccountingMetric {
+ CGROUP_IP_INGRESS_BYTES,
+ CGROUP_IP_INGRESS_PACKETS,
+ CGROUP_IP_EGRESS_BYTES,
+ CGROUP_IP_EGRESS_PACKETS,
+ _CGROUP_IP_ACCOUNTING_METRIC_MAX,
+ _CGROUP_IP_ACCOUNTING_METRIC_INVALID = -1,
+} CGroupIPAccountingMetric;
+
#include "unit.h"
void cgroup_context_init(CGroupContext *c);
@@ -145,6 +160,8 @@ CGroupMask unit_get_subtree_mask(Unit *u);
CGroupMask unit_get_target_mask(Unit *u);
CGroupMask unit_get_enable_mask(Unit *u);
+bool unit_get_needs_bpf(Unit *u);
+
void unit_update_cgroup_members_masks(Unit *u);
char *unit_default_cgroup_path(Unit *u);
@@ -155,12 +172,14 @@ void unit_release_cgroup(Unit *u);
void unit_prune_cgroup(Unit *u);
int unit_watch_cgroup(Unit *u);
+void unit_add_to_cgroup_empty_queue(Unit *u);
+
int unit_attach_pids_to_cgroup(Unit *u);
int manager_setup_cgroup(Manager *m);
void manager_shutdown_cgroup(Manager *m, bool delete);
-unsigned manager_dispatch_cgroup_queue(Manager *m);
+unsigned manager_dispatch_cgroup_realize_queue(Manager *m);
Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid);
@@ -172,14 +191,21 @@ int unit_watch_all_pids(Unit *u);
int unit_get_memory_current(Unit *u, uint64_t *ret);
int unit_get_tasks_current(Unit *u, uint64_t *ret);
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
-int unit_reset_cpu_usage(Unit *u);
+int unit_get_ip_accounting(Unit *u, CGroupIPAccountingMetric metric, uint64_t *ret);
+
+int unit_reset_cpu_accounting(Unit *u);
+int unit_reset_ip_accounting(Unit *u);
-bool unit_cgroup_delegate(Unit *u);
+#define UNIT_CGROUP_BOOL(u, name) \
+ ({ \
+ CGroupContext *cc = unit_get_cgroup_context(u); \
+ cc ? cc->name : false; \
+ })
-int unit_notify_cgroup_empty(Unit *u);
int manager_notify_cgroup_empty(Manager *m, const char *group);
void unit_invalidate_cgroup(Unit *u, CGroupMask m);
+void unit_invalidate_cgroup_bpf(Unit *u);
void manager_invalidate_startup_units(Manager *m);
diff --git a/src/core/chown-recursive.c b/src/core/chown-recursive.c
new file mode 100644
index 0000000000..2a3a0704f5
--- /dev/null
+++ b/src/core/chown-recursive.c
@@ -0,0 +1,152 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "user-util.h"
+#include "macro.h"
+#include "fd-util.h"
+#include "dirent-util.h"
+#include "chown-recursive.h"
+
+static int chown_one(int fd, const char *name, const struct stat *st, uid_t uid, gid_t gid) {
+ int r;
+
+ assert(fd >= 0);
+ assert(st);
+
+ if ((!uid_is_valid(uid) || st->st_uid == uid) &&
+ (!gid_is_valid(gid) || st->st_gid == gid))
+ return 0;
+
+ if (name)
+ r = fchownat(fd, name, uid, gid, AT_SYMLINK_NOFOLLOW);
+ else
+ r = fchown(fd, uid, gid);
+ if (r < 0)
+ return -errno;
+
+ /* The linux kernel alters the mode in some cases of chown(). Let's undo this. */
+ if (name) {
+ if (!S_ISLNK(st->st_mode))
+ r = fchmodat(fd, name, st->st_mode, 0);
+ else /* There's currently no AT_SYMLINK_NOFOLLOW for fchmodat() */
+ r = 0;
+ } else
+ r = fchmod(fd, st->st_mode);
+ if (r < 0)
+ return -errno;
+
+ return 1;
+}
+
+static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gid_t gid) {
+ bool changed = false;
+ int r;
+
+ assert(fd >= 0);
+ assert(st);
+
+ if (S_ISDIR(st->st_mode)) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+
+ d = fdopendir(fd);
+ if (!d) {
+ r = -errno;
+ goto finish;
+ }
+ fd = -1;
+
+ FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
+ struct stat fst;
+
+ if (dot_or_dot_dot(de->d_name))
+ continue;
+
+ if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (S_ISDIR(fst.st_mode)) {
+ int subdir_fd;
+
+ subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ r = chown_recursive_internal(subdir_fd, &fst, uid, gid);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ changed = true;
+ } else {
+ r = chown_one(dirfd(d), de->d_name, &fst, uid, gid);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ changed = true;
+ }
+ }
+
+ r = chown_one(dirfd(d), NULL, st, uid, gid);
+ } else
+ r = chown_one(fd, NULL, st, uid, gid);
+ if (r < 0)
+ goto finish;
+
+ r = r > 0 || changed;
+
+finish:
+ safe_close(fd);
+ return r;
+}
+
+int path_chown_recursive(const char *path, uid_t uid, gid_t gid) {
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ int r;
+
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (fd < 0)
+ return -errno;
+
+ if (!uid_is_valid(uid) && !gid_is_valid(gid))
+ return 0; /* nothing to do */
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ /* Let's take a shortcut: if the top-level directory is properly owned, we don't descend into the whole tree,
+ * under the assumption that all is OK anyway. */
+
+ if ((!uid_is_valid(uid) || st.st_uid == uid) &&
+ (!gid_is_valid(gid) || st.st_gid == gid))
+ return 0;
+
+ r = chown_recursive_internal(fd, &st, uid, gid);
+ fd = -1; /* we donated the fd to the call, regardless if it succeeded or failed */
+
+ return r;
+}
diff --git a/src/core/dbus-busname.h b/src/core/chown-recursive.h
index 8643d1a404..653169885e 100644
--- a/src/core/dbus-busname.h
+++ b/src/core/chown-recursive.h
@@ -3,7 +3,7 @@
/***
This file is part of systemd.
- Copyright 2013 Lennart Poettering
+ Copyright 2017 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
@@ -19,5 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/types.h>
-extern const sd_bus_vtable bus_busname_vtable[];
+int path_chown_recursive(const char *path, uid_t uid, gid_t gid);
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
deleted file mode 100644
index cf816ba15b..0000000000
--- a/src/core/dbus-busname.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/***
- 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 "bus-util.h"
-#include "busname.h"
-#include "dbus-busname.h"
-#include "string-util.h"
-#include "unit.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
-
-const sd_bus_vtable bus_busname_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Name", "s", NULL, offsetof(BusName, name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(BusName, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(BusName, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(BusName, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Activating", "b", bus_property_get_bool, offsetof(BusName, activating), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("AcceptFileDescriptors", "b", bus_property_get_bool, offsetof(BusName, accept_fd), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 12d3ca076b..a99d727f4d 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -17,7 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <arpa/inet.h>
+
+#include "af-list.h"
#include "alloc-util.h"
+#include "bpf-firewall.h"
#include "bus-util.h"
#include "cgroup-util.h"
#include "cgroup.h"
@@ -206,6 +210,48 @@ static int property_get_device_allow(
return sd_bus_message_close_container(reply);
}
+static int property_get_ip_address_access(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ IPAddressAccessItem** items = userdata, *i;
+ int r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(iayu)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(items, i, *items) {
+
+ r = sd_bus_message_open_container(reply, 'r', "iayu");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "i", i->family);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(reply, 'y', &i->address, FAMILY_ADDRESS_SIZE(i->family));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "u", (uint32_t) i->prefixlen);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
@@ -239,6 +285,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
+ SD_BUS_PROPERTY("IPAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, ip_accounting), 0),
+ SD_BUS_PROPERTY("IPAddressAllow", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_allow), 0),
+ SD_BUS_PROPERTY("IPAddressDeny", "a(iayu)", property_get_ip_address_access, offsetof(CGroupContext, ip_address_deny), 0),
SD_BUS_VTABLE_END
};
@@ -625,7 +674,7 @@ int bus_cgroup_set_property(
if (!f)
return -ENOMEM;
- fputs("IODeviceWeight=\n", f);
+ fputs_unlocked("IODeviceWeight=\n", f);
LIST_FOREACH(device_weights, a, c->io_device_weights)
fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
@@ -774,12 +823,12 @@ int bus_cgroup_set_property(
return -ENOMEM;
if (read) {
- fputs("BlockIOReadBandwidth=\n", f);
+ fputs_unlocked("BlockIOReadBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
if (a->rbps != CGROUP_LIMIT_MAX)
fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
} else {
- fputs("BlockIOWriteBandwidth=\n", f);
+ fputs_unlocked("BlockIOWriteBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
if (a->wbps != CGROUP_LIMIT_MAX)
fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
@@ -857,7 +906,7 @@ int bus_cgroup_set_property(
if (!f)
return -ENOMEM;
- fputs("BlockIODeviceWeight=\n", f);
+ fputs_unlocked("BlockIODeviceWeight=\n", f);
LIST_FOREACH(device_weights, a, c->blockio_device_weights)
fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
@@ -1018,8 +1067,8 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
- if ((!startswith(path, "/dev/") &&
- !startswith(path, "/run/systemd/inaccessible/") &&
+ if ((!path_startswith(path, "/dev/") &&
+ !path_startswith(path, "/run/systemd/inaccessible/") &&
!startswith(path, "block-") &&
!startswith(path, "char-")) ||
strpbrk(path, WHITESPACE))
@@ -1086,7 +1135,7 @@ int bus_cgroup_set_property(
if (!f)
return -ENOMEM;
- fputs("DeviceAllow=\n", f);
+ fputs_unlocked("DeviceAllow=\n", f);
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
@@ -1133,6 +1182,7 @@ int bus_cgroup_set_property(
}
return 1;
+
} else if (streq(name, "TasksMaxScale")) {
uint64_t limit;
uint32_t raw;
@@ -1153,6 +1203,137 @@ int bus_cgroup_set_property(
}
return 1;
+
+ } else if (streq(name, "IPAccounting")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->ip_accounting = b;
+
+ unit_invalidate_cgroup_bpf(u);
+ unit_write_drop_in_private(u, mode, name, b ? "IPAccounting=yes" : "IPAccounting=no");
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
+ IPAddressAccessItem **list;
+ size_t n = 0;
+
+ list = streq(name, "IPAddressAllow") ? &c->ip_address_allow : &c->ip_address_deny;
+
+ r = sd_bus_message_enter_container(message, 'a', "(iayu)");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const void *ap;
+ int32_t family;
+ uint32_t prefixlen;
+ size_t an;
+
+ r = sd_bus_message_enter_container(message, 'r', "iayu");
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_read(message, "i", &family);
+ if (r < 0)
+ return r;
+
+ if (!IN_SET(family, AF_INET, AF_INET6))
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= expects IPv4 or IPv6 addresses only.", name);
+
+ r = sd_bus_message_read_array(message, 'y', &ap, &an);
+ if (r < 0)
+ return r;
+
+ if (an != FAMILY_ADDRESS_SIZE(family))
+ return sd_bus_error_set_errnof(error, EINVAL, "IP address has wrong size for family (%s, expected %zu, got %zu)",
+ af_to_name(family), FAMILY_ADDRESS_SIZE(family), an);
+
+ r = sd_bus_message_read(message, "u", &prefixlen);
+ if (r < 0)
+ return r;
+
+ if (prefixlen > FAMILY_ADDRESS_SIZE(family)*8)
+ return sd_bus_error_set_errnof(error, EINVAL, "Prefix length %" PRIu32 " too large for address family %s.", prefixlen, af_to_name(family));
+
+ if (mode != UNIT_CHECK) {
+ IPAddressAccessItem *item;
+
+ item = new0(IPAddressAccessItem, 1);
+ if (!item)
+ return -ENOMEM;
+
+ item->family = family;
+ item->prefixlen = prefixlen;
+ memcpy(&item->address, ap, an);
+
+ LIST_PREPEND(items, *list, item);
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ n++;
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ *list = ip_address_access_reduce(*list);
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ IPAddressAccessItem *item;
+ size_t size = 0;
+
+ if (n == 0)
+ *list = ip_address_access_free_all(*list);
+
+ unit_invalidate_cgroup_bpf(u);
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fputs_unlocked(name, f);
+ fputs_unlocked("=\n", f);
+
+ LIST_FOREACH(items, item, *list) {
+ char buffer[CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)];
+
+ errno = 0;
+ if (!inet_ntop(item->family, &item->address, buffer, sizeof(buffer)))
+ return errno > 0 ? -errno : -EINVAL;
+
+ fprintf(f, "%s=%s/%u\n", name, buffer, item->prefixlen);
+ }
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private(u, mode, name, buf);
+
+ if (*list) {
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0)
+ log_warning("Transient unit %s configures an IP firewall, but the local system does not support BPF/cgroup firewalling.\n"
+ "Proceeding WITHOUT firewalling in effect!", u->id);
+ }
+ }
+
+ return 1;
}
if (u->transient && u->load_state == UNIT_STUB) {
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index a5b8eaca87..d211ff11b5 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -19,7 +19,7 @@
#include <sys/prctl.h>
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include <seccomp.h>
#endif
@@ -27,8 +27,10 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "capability-util.h"
+#include "cap-list.h"
#include "dbus-execute.h"
#include "env-util.h"
+#include "errno-list.h"
#include "execute.h"
#include "fd-util.h"
#include "fileio.h"
@@ -40,9 +42,10 @@
#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "securebits-util.h"
#include "strv.h"
#include "syslog-util.h"
#include "unit-printf.h"
@@ -50,10 +53,11 @@
#include "utf8.h"
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
-
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_preserve_mode, exec_preserve_mode, ExecPreserveMode);
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode);
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_home, protect_home, ProtectHome);
static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
@@ -402,7 +406,7 @@ static int property_get_syscall_filter(
_cleanup_strv_free_ char **l = NULL;
int r;
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
Iterator i;
void *id;
#endif
@@ -419,7 +423,7 @@ static int property_get_syscall_filter(
if (r < 0)
return r;
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
SET_FOREACH(id, c->syscall_filter, i) {
char *name;
@@ -455,7 +459,7 @@ static int property_get_syscall_archs(
_cleanup_strv_free_ char **l = NULL;
int r;
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
Iterator i;
void *id;
#endif
@@ -464,7 +468,7 @@ static int property_get_syscall_archs(
assert(reply);
assert(c);
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
SET_FOREACH(id, c->syscall_archs, i) {
const char *name;
@@ -783,6 +787,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("UnsetEnvironment", "as", NULL, offsetof(ExecContext, unset_environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("LimitCPUSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -878,15 +883,26 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SystemCallArchitectures", "as", property_get_syscall_archs, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SystemCallErrorNumber", "i", property_get_syscall_errno, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Personality", "s", property_get_personality, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LockPersonality", "b", bus_property_get_bool, offsetof(ExecContext, lock_personality), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectoryPreserve", "s", property_get_exec_preserve_mode, offsetof(ExecContext, runtime_directory_preserve_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_RUNTIME].paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StateDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StateDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_STATE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("CacheDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("CacheDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CACHE].paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogsDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LogsDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_LOGS].paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ConfigurationDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].mode), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
/* Obsolete/redundant properties: */
SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -920,7 +936,7 @@ static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
return r;
r = sd_bus_message_append(reply, "bttttuii",
- c->ignore,
+ !!(c->flags & EXEC_COMMAND_IGNORE_FAILURE),
c->exec_status.start_timestamp.realtime,
c->exec_status.start_timestamp.monotonic,
c->exec_status.exit_timestamp.realtime,
@@ -1047,6 +1063,41 @@ int bus_exec_context_set_transient_property(
}
return 1;
+
+ } else if (streq(name, "SupplementaryGroups")) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ if (!isempty(*p) && !valid_user_group_name_or_id(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supplementary group names");
+ }
+
+ if (mode != UNIT_CHECK) {
+ if (strv_length(l) == 0) {
+ c->supplementary_groups = strv_free(c->supplementary_groups);
+ unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+ } else {
+ _cleanup_free_ char *joined = NULL;
+
+ r = strv_extend_strv(&c->supplementary_groups, l, true);
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join(c->supplementary_groups, " ");
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
+ }
+ }
+
+ return 1;
+
} else if (streq(name, "SyslogIdentifier")) {
const char *id;
@@ -1097,6 +1148,361 @@ int bus_exec_context_set_transient_property(
}
return 1;
+ } else if (streq(name, "SecureBits")) {
+ int n;
+
+ r = sd_bus_message_read(message, "i", &n);
+ if (r < 0)
+ return r;
+
+ if (!secure_bits_is_valid(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid secure bits");
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *str = NULL;
+
+ c->secure_bits = n;
+ r = secure_bits_to_string_alloc(n, &str);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private_format(u, mode, name, "SecureBits=%s", str);
+ }
+
+ return 1;
+ } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
+ uint64_t n;
+
+ r = sd_bus_message_read(message, "t", &n);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *str = NULL;
+
+ if (streq(name, "CapabilityBoundingSet"))
+ c->capability_bounding_set = n;
+ else /* "AmbientCapabilities" */
+ c->capability_ambient_set = n;
+
+ r = capability_set_to_string_alloc(n, &str);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str);
+ }
+
+ return 1;
+
+ } else if (streq(name, "Personality")) {
+ const char *s;
+ unsigned long p;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ p = personality_from_string(s);
+ if (p == PERSONALITY_INVALID)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid personality");
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *str = NULL;
+
+ c->personality = p;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
+ }
+
+ return 1;
+
+#if HAVE_SECCOMP
+
+ } else if (streq(name, "SystemCallFilter")) {
+ int whitelist;
+ _cleanup_strv_free_ char **l;
+
+ r = sd_bus_message_enter_container(message, 'r', "bas");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read(message, "b", &whitelist);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_length(l) == 0) {
+ c->syscall_whitelist = false;
+ c->syscall_filter = set_free(c->syscall_filter);
+ } else {
+ char **s;
+
+ c->syscall_whitelist = whitelist;
+
+ r = set_ensure_allocated(&c->syscall_filter, NULL);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(s, l) {
+ if (**s == '@') {
+ const SyscallFilterSet *set;
+ const char *i;
+
+ set = syscall_filter_set_find(*s);
+ if (!set)
+ return -EINVAL;
+
+ NULSTR_FOREACH(i, set->value) {
+ int id;
+
+ id = seccomp_syscall_resolve_name(i);
+ if (id == __NR_SCMP_ERROR)
+ return -EINVAL;
+
+ r = set_put(c->address_families, INT_TO_PTR(id + 1));
+ if (r < 0)
+ return r;
+ }
+
+ } else {
+ int id;
+
+ id = seccomp_syscall_resolve_name(*s);
+ if (id == __NR_SCMP_ERROR)
+ return -EINVAL;
+
+ r = set_put(c->address_families, INT_TO_PTR(id + 1));
+ if (r < 0)
+ return r;
+ }
+ }
+ }
+
+ joined = strv_join(l, " ");
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "SystemCallFilter=%s%s", whitelist ? "" : "~", joined);
+ }
+
+ return 1;
+
+ } else if (streq(name, "SystemCallArchitectures")) {
+ _cleanup_strv_free_ char **l = NULL;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_length(l) == 0)
+ c->syscall_archs = set_free(c->syscall_archs);
+ else {
+ char **s;
+
+ r = set_ensure_allocated(&c->syscall_archs, NULL);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(s, l) {
+ uint32_t a;
+
+ r = seccomp_arch_from_string(*s, &a);
+ if (r < 0)
+ return r;
+
+ r = set_put(c->syscall_archs, UINT32_TO_PTR(a + 1));
+ if (r < 0)
+ return r;
+ }
+
+ }
+
+ joined = strv_join(l, " ");
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
+ }
+
+ return 1;
+
+ } else if (streq(name, "SystemCallErrorNumber")) {
+ int32_t n;
+ const char *str;
+
+ r = sd_bus_message_read(message, "i", &n);
+ if (r < 0)
+ return r;
+
+ str = errno_to_name(n);
+ if (!str)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SystemCallErrorNumber");
+
+ if (mode != UNIT_CHECK) {
+ c->syscall_errno = n;
+
+ unit_write_drop_in_private_format(u, mode, name, "SystemCallErrorNumber=%s", str);
+ }
+
+ return 1;
+
+ } else if (streq(name, "RestrictAddressFamilies")) {
+ int whitelist;
+ _cleanup_strv_free_ char **l;
+
+ r = sd_bus_message_enter_container(message, 'r', "bas");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read(message, "b", &whitelist);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_length(l) == 0) {
+ c->address_families_whitelist = false;
+ c->address_families = set_free(c->address_families);
+ } else {
+ char **s;
+
+ c->address_families_whitelist = whitelist;
+
+ r = set_ensure_allocated(&c->address_families, NULL);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(s, l) {
+ int af;
+
+ af = af_from_name(*s);
+ if (af <= 0)
+ return -EINVAL;
+
+ r = set_put(c->address_families, INT_TO_PTR(af));
+ if (r < 0)
+ return r;
+ }
+ }
+
+ joined = strv_join(l, " ");
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "RestrictAddressFamilies=%s%s", whitelist ? "" : "~", joined);
+ }
+
+ return 1;
+#endif
+
+ } else if (streq(name, "CPUSchedulingPolicy")) {
+ int32_t n;
+
+ r = sd_bus_message_read(message, "i", &n);
+ if (r < 0)
+ return r;
+
+ if (!sched_policy_is_valid(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling policy");
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *str = NULL;
+
+ c->cpu_sched_policy = n;
+ r = sched_policy_to_string_alloc(n, &str);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPolicy=%s", str);
+ }
+
+ return 1;
+
+ } else if (streq(name, "CPUSchedulingPriority")) {
+ int32_t n;
+
+ r = sd_bus_message_read(message, "i", &n);
+ if (r < 0)
+ return r;
+
+ if (!ioprio_priority_is_valid(n))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid CPU scheduling priority");
+
+ if (mode != UNIT_CHECK) {
+ c->cpu_sched_priority = n;
+ unit_write_drop_in_private_format(u, mode, name, "CPUSchedulingPriority=%i", n);
+ }
+
+ return 1;
+
+ } else if (streq(name, "CPUAffinity")) {
+ const void *a;
+ size_t n = 0;
+
+ r = sd_bus_message_read_array(message, 'y', &a, &n);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (n == 0) {
+ c->cpuset = mfree(c->cpuset);
+ unit_write_drop_in_private_format(u, mode, name, "%s=", name);
+ } else {
+ _cleanup_free_ char *str = NULL;
+ uint8_t *l;
+ size_t allocated = 0, len = 0, i;
+
+ c->cpuset = (cpu_set_t*) memdup(a, sizeof(cpu_set_t) * n);
+ if (c->cpuset)
+ return -ENOMEM;
+
+ l = (uint8_t*) a;
+ for (i = 0; i < n; i++) {
+ _cleanup_free_ char *p = NULL;
+ size_t add;
+
+ r = asprintf(&p, "%hhi", l[i]);
+ if (r < 0)
+ return -ENOMEM;
+
+ add = strlen(p);
+
+ if (GREEDY_REALLOC(str, allocated, len + add + 2))
+ return -ENOMEM;
+
+ strcpy(mempcpy(str + len, p, add), " ");
+ len += add + 1;
+ }
+
+ if (len != 0)
+ str[len - 1] = '\0';
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, str);
+ }
+ }
+
+ return 1;
} else if (streq(name, "Nice")) {
int32_t n;
@@ -1316,11 +1722,12 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (STR_IN_SET(name,
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
+ "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
"NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute",
"RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables",
- "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS")) {
+ "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
+ "CPUSchedulingResetOnFork", "NonBlocking", "LockPersonality")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -1334,6 +1741,8 @@ int bus_exec_context_set_transient_property(
c->tty_vhangup = b;
else if (streq(name, "TTYReset"))
c->tty_reset = b;
+ else if (streq(name, "TTYVTDisallocate"))
+ c->tty_vt_disallocate = b;
else if (streq(name, "PrivateTmp"))
c->private_tmp = b;
else if (streq(name, "PrivateDevices"))
@@ -1362,6 +1771,12 @@ int bus_exec_context_set_transient_property(
c->protect_control_groups = b;
else if (streq(name, "MountAPIVFS"))
c->mount_apivfs = b;
+ else if (streq(name, "CPUSchedulingResetOnFork"))
+ c->cpu_sched_reset_on_fork = b;
+ else if (streq(name, "NonBlocking"))
+ c->non_blocking = b;
+ else if (streq(name, "LockPersonality"))
+ c->lock_personality = b;
unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b));
}
@@ -1432,13 +1847,13 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
- if (!strv_env_is_valid(l))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
-
r = unit_full_printf_strv(u, l, &q);
if (r < 0)
return r;
+ if (!strv_env_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
+
if (mode != UNIT_CHECK) {
if (strv_length(q) == 0) {
c->environment = strv_free(c->environment);
@@ -1455,7 +1870,7 @@ int bus_exec_context_set_transient_property(
c->environment = e;
/* We write just the new settings out to file, with unresolved specifiers */
- joined = strv_join_quoted(q);
+ joined = strv_join_quoted(l);
if (!joined)
return -ENOMEM;
@@ -1465,6 +1880,47 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "UnsetEnvironment")) {
+
+ _cleanup_strv_free_ char **l = NULL, **q = NULL;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ r = unit_full_printf_strv(u, l, &q);
+ if (r < 0)
+ return r;
+
+ if (!strv_env_name_or_assignment_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UnsetEnvironment= list.");
+
+ if (mode != UNIT_CHECK) {
+ if (strv_length(q) == 0) {
+ c->unset_environment = strv_free(c->unset_environment);
+ unit_write_drop_in_private_format(u, mode, name, "UnsetEnvironment=");
+ } else {
+ _cleanup_free_ char *joined = NULL;
+ char **e;
+
+ e = strv_env_merge(2, c->unset_environment, q);
+ if (!e)
+ return -ENOMEM;
+
+ strv_free(c->unset_environment);
+ c->unset_environment = e;
+
+ /* We write just the new settings out to file, with unresolved specifiers */
+ joined = strv_join_quoted(l);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "UnsetEnvironment=%s", joined);
+ }
+ }
+
+ return 1;
+
} else if (streq(name, "TimerSlackNSec")) {
nsec_t n;
@@ -1533,7 +1989,7 @@ int bus_exec_context_set_transient_property(
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
if (mode != UNIT_CHECK) {
- char *buf = NULL;
+ char *buf;
buf = strjoin(b ? "-" : "", path);
if (!buf)
@@ -1574,14 +2030,18 @@ int bus_exec_context_set_transient_property(
} else if (streq(name, "PassEnvironment")) {
- _cleanup_strv_free_ char **l = NULL;
+ _cleanup_strv_free_ char **l = NULL, **q = NULL;
r = sd_bus_message_read_strv(message, &l);
if (r < 0)
return r;
- if (!strv_env_name_is_valid(l))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block.");
+ r = unit_full_printf_strv(u, l, &q);
+ if (r < 0)
+ return r;
+
+ if (!strv_env_name_is_valid(q))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment= block.");
if (mode != UNIT_CHECK) {
if (strv_isempty(l)) {
@@ -1590,11 +2050,12 @@ int bus_exec_context_set_transient_property(
} else {
_cleanup_free_ char *joined = NULL;
- r = strv_extend_strv(&c->pass_environment, l, true);
+ r = strv_extend_strv(&c->pass_environment, q, true);
if (r < 0)
return r;
- joined = strv_join_quoted(c->pass_environment);
+ /* We write just the new settings out to file, with unresolved specifiers. */
+ joined = strv_join_quoted(l);
if (!joined)
return -ENOMEM;
@@ -1708,7 +2169,72 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (streq(name, "RuntimeDirectory")) {
+ } else if (streq(name, "KeyringMode")) {
+
+ const char *s;
+ ExecKeyringMode m;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ m = exec_keyring_mode_from_string(s);
+ if (m < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid keyring mode");
+
+ if (mode != UNIT_CHECK) {
+ c->keyring_mode = m;
+
+ unit_write_drop_in_private_format(u, mode, name, "KeyringMode=%s", exec_keyring_mode_to_string(m));
+ }
+
+ return 1;
+
+ } else if (streq(name, "RuntimeDirectoryPreserve")) {
+ const char *s;
+ ExecPreserveMode m;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ m = exec_preserve_mode_from_string(s);
+ if (m < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid preserve mode");
+
+ if (mode != UNIT_CHECK) {
+ c->runtime_directory_preserve_mode = m;
+
+ unit_write_drop_in_private_format(u, mode, name, "RuntimeDirectoryPreserve=%s", exec_preserve_mode_to_string(m));
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) {
+ mode_t m;
+
+ r = sd_bus_message_read(message, "u", &m);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ ExecDirectoryType i;
+
+ if (streq(name, "UMask"))
+ c->umask = m;
+ else
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
+ if (startswith(name, exec_directory_type_to_string(i))) {
+ c->directories[i].mode = m;
+ break;
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%040o", name, m);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
_cleanup_strv_free_ char **l = NULL;
char **p;
@@ -1717,23 +2243,32 @@ int bus_exec_context_set_transient_property(
return r;
STRV_FOREACH(p, l) {
- if (!filename_is_valid(*p))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
+ if (!path_is_safe(*p) || path_is_absolute(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s= path is not valid: %s", name, *p);
}
if (mode != UNIT_CHECK) {
_cleanup_free_ char *joined = NULL;
+ char ***dirs = NULL;
+ ExecDirectoryType i;
+
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
+ if (streq(name, exec_directory_type_to_string(i))) {
+ dirs = &c->directories[i].paths;
+ break;
+ }
+
+ assert(dirs);
if (strv_isempty(l)) {
- c->runtime_directory = strv_free(c->runtime_directory);
+ *dirs = strv_free(*dirs);
unit_write_drop_in_private_format(u, mode, name, "%s=", name);
} else {
- r = strv_extend_strv(&c->runtime_directory, l, true);
-
+ r = strv_extend_strv(dirs, l, true);
if (r < 0)
return -ENOMEM;
- joined = strv_join_quoted(c->runtime_directory);
+ joined = strv_join_quoted(*dirs);
if (!joined)
return -ENOMEM;
@@ -1745,7 +2280,6 @@ int bus_exec_context_set_transient_property(
} else if (streq(name, "SELinuxContext")) {
const char *s;
-
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
@@ -1760,6 +2294,45 @@ int bus_exec_context_set_transient_property(
}
return 1;
+
+ } else if (STR_IN_SET(name, "AppArmorProfile", "SmackProcessLabel")) {
+ int ignore;
+ const char *s;
+
+ r = sd_bus_message_enter_container(message, 'r', "bs");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read(message, "bs", &ignore, &s);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ char **p;
+ bool *b;
+
+ if (streq(name, "AppArmorProfile")) {
+ p = &c->apparmor_profile;
+ b = &c->apparmor_profile_ignore;
+ } else { /* "SmackProcessLabel" */
+ p = &c->smack_process_label;
+ b = &c->smack_process_label_ignore;
+ }
+
+ if (isempty(s)) {
+ *p = mfree(*p);
+ *b = false;
+ } else {
+ if (free_and_strdup(p, s) < 0)
+ return -ENOMEM;
+ *b = ignore;
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s%s", name, ignore ? "-" : "", strempty(s));
+ }
+
+ return 1;
+
} else if (streq(name, "RestrictNamespaces")) {
uint64_t flags;
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 6458ee5c12..05bdc0a748 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -67,6 +67,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("UID", "u", NULL, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("GID", "u", NULL, offsetof(Unit, ref_gid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("NRestarts", "u", bus_property_get_unsigned, offsetof(Service, n_restarts), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -279,7 +280,7 @@ static int bus_service_set_transient_property(
c->argv = argv;
argv = NULL;
- c->ignore = b;
+ c->flags = b ? EXEC_COMMAND_IGNORE_FAILURE : 0;
path_kill_slashes(c->path);
exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
@@ -308,7 +309,7 @@ static int bus_service_set_transient_property(
if (!f)
return -ENOMEM;
- fputs("ExecStart=\n", f);
+ fputs_unlocked("ExecStart=\n", f);
LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
_cleanup_free_ char *a;
@@ -318,7 +319,7 @@ static int bus_service_set_transient_property(
return -ENOMEM;
fprintf(f, "ExecStart=%s@%s %s\n",
- c->ignore ? "-" : "",
+ c->flags & EXEC_COMMAND_IGNORE_FAILURE ? "-" : "",
c->path,
a);
}
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index b0645ce294..a9a68826b4 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -20,6 +20,7 @@
#include "sd-bus.h"
#include "alloc-util.h"
+#include "bpf-firewall.h"
#include "bus-common-errors.h"
#include "cgroup-util.h"
#include "dbus-job.h"
@@ -916,7 +917,7 @@ static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *
assert(pid > 0);
r = set_put(pids, PID_TO_PTR(pid));
- if (r == -EEXIST || r == 0)
+ if (IN_SET(r, 0, -EEXIST))
return 0;
if (r < 0)
return r;
@@ -1051,6 +1052,39 @@ int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bu
return sd_bus_send(NULL, reply, NULL);
}
+static int property_get_ip_counter(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupIPAccountingMetric metric;
+ uint64_t value = (uint64_t) -1;
+ Unit *u = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(property);
+ assert(u);
+
+ if (streq(property, "IPIngressBytes"))
+ metric = CGROUP_IP_INGRESS_BYTES;
+ else if (streq(property, "IPIngressPackets"))
+ metric = CGROUP_IP_INGRESS_PACKETS;
+ else if (streq(property, "IPEgressBytes"))
+ metric = CGROUP_IP_EGRESS_BYTES;
+ else {
+ assert(streq(property, "IPEgressPackets"));
+ metric = CGROUP_IP_EGRESS_PACKETS;
+ }
+
+ (void) unit_get_ip_accounting(u, metric, &value);
+ return sd_bus_message_append(reply, "t", value);
+}
+
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
@@ -1058,6 +1092,10 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
+ SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0),
+ SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0),
+ SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0),
+ SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0),
SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
@@ -1215,13 +1253,13 @@ int bus_unit_queue_job(
}
if (type == JOB_STOP &&
- (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
+ (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR)) &&
unit_active_state(u) == UNIT_INACTIVE)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
if ((type == JOB_START && u->refuse_manual_start) ||
(type == JOB_STOP && u->refuse_manual_stop) ||
- ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+ (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
(type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
diff --git a/src/core/dbus.c b/src/core/dbus.c
index a56578dfc7..7fed45b95c 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -92,7 +92,7 @@ int bus_forward_agent_released(Manager *m, const char *path) {
"Released",
"s", path);
if (r < 0)
- return log_warning_errno(r, "Failed to propagate agent release message: %m");
+ return log_debug_errno(r, "Failed to propagate agent release message: %m");
return 1;
}
@@ -211,7 +211,7 @@ failed:
return 0;
}
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *verb, *path;
@@ -535,7 +535,7 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
r = sd_bus_add_filter(bus, NULL, mac_selinux_filter, m);
if (r < 0)
return log_error_errno(r, "Failed to add SELinux access filter: %m");
@@ -971,7 +971,7 @@ static int bus_init_private(Manager *m) {
if (MANAGER_IS_SYSTEM(m)) {
/* We want the private bus only when running as init */
- if (getpid() != 1)
+ if (getpid_cached() != 1)
return 0;
strcpy(sa.un.sun_path, "/run/systemd/private");
diff --git a/src/core/device.c b/src/core/device.c
index 48fa262c8c..a5d701fbfe 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -514,7 +514,7 @@ static void device_update_found_one(Device *d, bool add, DeviceFound found, bool
}
static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
- Device *d, *l;
+ Device *d, *l, *n;
assert(m);
assert(sysfs);
@@ -523,7 +523,7 @@ static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add,
return 0;
l = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_FOREACH(same_sysfs, d, l)
+ LIST_FOREACH_SAFE(same_sysfs, d, n, l)
device_update_found_one(d, add, found, now);
return 0;
diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c
index e1846e1adb..f1b5ee7ecb 100644
--- a/src/core/dynamic-user.c
+++ b/src/core/dynamic-user.c
@@ -21,15 +21,17 @@
#include <pwd.h>
#include <sys/file.h>
+#include "clean-ipc.h"
#include "dynamic-user.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
+#include "io-util.h"
#include "parse-util.h"
#include "random-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "user-util.h"
-#include "fileio.h"
/* Takes a value generated randomly or by hashing and turns it into a UID in the right range */
#define UID_CLAMP_INTO_RANGE(rnd) (((uid_t) (rnd) % (DYNAMIC_UID_MAX - DYNAMIC_UID_MIN + 1)) + DYNAMIC_UID_MIN)
@@ -181,33 +183,89 @@ static int make_uid_symlinks(uid_t uid, const char *name, bool b) {
return r;
}
-static int pick_uid(const char *name, uid_t *ret_uid) {
+static int pick_uid(char **suggested_paths, const char *name, uid_t *ret_uid) {
+
+ /* Find a suitable free UID. We use the following strategy to find a suitable UID:
+ *
+ * 1. Initially, we try to read the UID of a number of specified paths. If any of these UIDs works, we use
+ * them. We use in order to increase the chance of UID reuse, if StateDirectory=, CacheDirectory= or
+ * LogDirectory= are used, as reusing the UID these directories are owned by saves us from having to
+ * recursively chown() them to new users.
+ *
+ * 2. If that didn't yield a currently unused UID, we hash the user name, and try to use that. This should be
+ * pretty good, as the use ris by default derived from the unit name, and hence the same service and same
+ * user should usually get the same UID as long as our hashing doesn't clash.
+ *
+ * 3. Finally, if that didn't work, we randomly pick UIDs, until we find one that is empty.
+ *
+ * Since the dynamic UID space is relatively small we'll stop trying after 100 iterations, giving up. */
+
+ enum {
+ PHASE_SUGGESTED, /* the first phase, reusing directory ownership UIDs */
+ PHASE_HASHED, /* the second phase, deriving a UID from the username by hashing */
+ PHASE_RANDOM, /* the last phase, randomly picking UIDs */
+ } phase = PHASE_SUGGESTED;
static const uint8_t hash_key[] = {
0x37, 0x53, 0x7e, 0x31, 0xcf, 0xce, 0x48, 0xf5,
0x8a, 0xbb, 0x39, 0x57, 0x8d, 0xd9, 0xec, 0x59
};
- unsigned n_tries = 100;
- uid_t candidate;
+ unsigned n_tries = 100, current_suggested = 0;
int r;
- /* A static user by this name does not exist yet. Let's find a free ID then, and use that. We start with a UID
- * generated as hash from the user name. */
- candidate = UID_CLAMP_INTO_RANGE(siphash24(name, strlen(name), hash_key));
-
(void) mkdir("/run/systemd/dynamic-uid", 0755);
for (;;) {
char lock_path[strlen("/run/systemd/dynamic-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
_cleanup_close_ int lock_fd = -1;
+ uid_t candidate;
ssize_t l;
if (--n_tries <= 0) /* Give up retrying eventually */
return -EBUSY;
+ switch (phase) {
+
+ case PHASE_SUGGESTED: {
+ struct stat st;
+
+ if (!suggested_paths || !suggested_paths[current_suggested]) {
+ /* We reached the end of the suggested paths list, let's try by hashing the name */
+ phase = PHASE_HASHED;
+ continue;
+ }
+
+ if (stat(suggested_paths[current_suggested++], &st) < 0)
+ continue; /* We can't read the UID of this path, but that doesn't matter, just try the next */
+
+ candidate = st.st_uid;
+ break;
+ }
+
+ case PHASE_HASHED:
+ /* A static user by this name does not exist yet. Let's find a free ID then, and use that. We
+ * start with a UID generated as hash from the user name. */
+ candidate = UID_CLAMP_INTO_RANGE(siphash24(name, strlen(name), hash_key));
+
+ /* If this one fails, we should proceed with random tries */
+ phase = PHASE_RANDOM;
+ break;
+
+ case PHASE_RANDOM:
+
+ /* Pick another random UID, and see if that works for us. */
+ random_bytes(&candidate, sizeof(candidate));
+ candidate = UID_CLAMP_INTO_RANGE(candidate);
+ break;
+
+ default:
+ assert_not_reached("unknown phase");
+ }
+
+ /* Make sure whatever we picked here actually is in the right range */
if (!uid_is_dynamic(candidate))
- goto next;
+ continue;
xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, candidate);
@@ -220,7 +278,7 @@ static int pick_uid(const char *name, uid_t *ret_uid) {
r = flock(lock_fd, LOCK_EX|LOCK_NB); /* Try to get a BSD file lock on the UID lock file */
if (r < 0) {
- if (errno == EBUSY || errno == EAGAIN)
+ if (IN_SET(errno, EBUSY, EAGAIN))
goto next; /* already in use */
return -errno;
@@ -237,20 +295,23 @@ static int pick_uid(const char *name, uid_t *ret_uid) {
}
/* Some superficial check whether this UID/GID might already be taken by some static user */
- if (getpwuid(candidate) || getgrgid((gid_t) candidate)) {
+ if (getpwuid(candidate) ||
+ getgrgid((gid_t) candidate) ||
+ search_ipc(candidate, (gid_t) candidate) != 0) {
(void) unlink(lock_path);
- goto next;
+ continue;
}
/* Let's store the user name in the lock file, so that we can use it for looking up the username for a UID */
l = pwritev(lock_fd,
(struct iovec[2]) {
- { .iov_base = (char*) name, .iov_len = strlen(name) },
- { .iov_base = (char[1]) { '\n' }, .iov_len = 1 }
+ IOVEC_INIT_STRING(name),
+ IOVEC_INIT((char[1]) { '\n' }, 1),
}, 2, 0);
if (l < 0) {
+ r = -errno;
(void) unlink(lock_path);
- return -errno;
+ return r;
}
(void) ftruncate(lock_fd, l);
@@ -263,18 +324,13 @@ static int pick_uid(const char *name, uid_t *ret_uid) {
return r;
next:
- /* Pick another random UID, and see if that works for us. */
- random_bytes(&candidate, sizeof(candidate));
- candidate = UID_CLAMP_INTO_RANGE(candidate);
+ ;
}
}
static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) {
uid_t uid = UID_INVALID;
- struct iovec iov = {
- .iov_base = &uid,
- .iov_len = sizeof(uid),
- };
+ struct iovec iov = IOVEC_INIT(&uid, sizeof(uid));
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -314,10 +370,7 @@ static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) {
}
static int dynamic_user_push(DynamicUser *d, uid_t uid, int lock_fd) {
- struct iovec iov = {
- .iov_base = &uid,
- .iov_len = sizeof(uid),
- };
+ struct iovec iov = IOVEC_INIT(&uid, sizeof(uid));
union {
struct cmsghdr cmsghdr;
uint8_t buf[CMSG_SPACE(sizeof(int))];
@@ -368,7 +421,7 @@ static void unlink_uid_lock(int lock_fd, uid_t uid, const char *name) {
(void) make_uid_symlinks(uid, name, false); /* remove direct lookup symlinks */
}
-int dynamic_user_realize(DynamicUser *d, uid_t *ret) {
+int dynamic_user_realize(DynamicUser *d, char **suggested_dirs, uid_t *ret) {
_cleanup_close_ int etc_passwd_lock_fd = -1, uid_lock_fd = -1;
uid_t uid = UID_INVALID;
@@ -426,7 +479,7 @@ int dynamic_user_realize(DynamicUser *d, uid_t *ret) {
if (uid == UID_INVALID) {
/* No static UID assigned yet, excellent. Let's pick a new dynamic one, and lock it. */
- uid_lock_fd = pick_uid(d->name, &uid);
+ uid_lock_fd = pick_uid(suggested_dirs, d->name, &uid);
if (uid_lock_fd < 0)
return uid_lock_fd;
}
@@ -749,7 +802,7 @@ int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, con
return 0;
}
-int dynamic_creds_realize(DynamicCreds *creds, uid_t *uid, gid_t *gid) {
+int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *uid, gid_t *gid) {
uid_t u = UID_INVALID;
gid_t g = GID_INVALID;
int r;
@@ -761,13 +814,13 @@ int dynamic_creds_realize(DynamicCreds *creds, uid_t *uid, gid_t *gid) {
/* Realize both the referenced user and group */
if (creds->user) {
- r = dynamic_user_realize(creds->user, &u);
+ r = dynamic_user_realize(creds->user, suggested_paths, &u);
if (r < 0)
return r;
}
if (creds->group && creds->group != creds->user) {
- r = dynamic_user_realize(creds->group, &g);
+ r = dynamic_user_realize(creds->group, suggested_paths, &g);
if (r < 0)
return r;
} else
diff --git a/src/core/dynamic-user.h b/src/core/dynamic-user.h
index 0b8bce1a72..e7de4f46ae 100644
--- a/src/core/dynamic-user.h
+++ b/src/core/dynamic-user.h
@@ -45,7 +45,7 @@ struct DynamicUser {
int dynamic_user_acquire(Manager *m, const char *name, DynamicUser **ret);
-int dynamic_user_realize(DynamicUser *d, uid_t *ret);
+int dynamic_user_realize(DynamicUser *d, char **suggested_paths, uid_t *ret);
int dynamic_user_current(DynamicUser *d, uid_t *ret);
DynamicUser* dynamic_user_ref(DynamicUser *d);
@@ -60,7 +60,7 @@ int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret);
int dynamic_user_lookup_name(Manager *m, const char *name, uid_t *ret);
int dynamic_creds_acquire(DynamicCreds *creds, Manager *m, const char *user, const char *group);
-int dynamic_creds_realize(DynamicCreds *creds, uid_t *uid, gid_t *gid);
+int dynamic_creds_realize(DynamicCreds *creds, char **suggested_paths, uid_t *uid, gid_t *gid);
void dynamic_creds_unref(DynamicCreds *creds);
void dynamic_creds_destroy(DynamicCreds *creds);
diff --git a/src/core/execute.c b/src/core/execute.c
index 92951089a5..26971320f2 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -37,19 +37,19 @@
#include <unistd.h>
#include <utmpx.h>
-#ifdef HAVE_PAM
+#if HAVE_PAM
#include <security/pam_appl.h>
#endif
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include <seccomp.h>
#endif
-#ifdef HAVE_APPARMOR
+#if HAVE_APPARMOR
#include <sys/apparmor.h>
#endif
@@ -57,13 +57,14 @@
#include "af-list.h"
#include "alloc-util.h"
-#ifdef HAVE_APPARMOR
+#if HAVE_APPARMOR
#include "apparmor-util.h"
#endif
#include "async.h"
#include "barrier.h"
#include "cap-list.h"
#include "capability-util.h"
+#include "chown-recursive.h"
#include "def.h"
#include "env-util.h"
#include "errno-list.h"
@@ -76,6 +77,7 @@
#include "glob-util.h"
#include "io-util.h"
#include "ioprio.h"
+#include "label.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
@@ -86,10 +88,11 @@
#include "process-util.h"
#include "rlimit-util.h"
#include "rm-rf.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "securebits.h"
+#include "securebits-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "smack-util.h"
@@ -242,6 +245,18 @@ static bool is_terminal_output(ExecOutput o) {
EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
}
+static bool is_syslog_output(ExecOutput o) {
+ return IN_SET(o,
+ EXEC_OUTPUT_SYSLOG,
+ EXEC_OUTPUT_SYSLOG_AND_CONSOLE);
+}
+
+static bool is_kmsg_output(ExecOutput o) {
+ return IN_SET(o,
+ EXEC_OUTPUT_KMSG,
+ EXEC_OUTPUT_KMSG_AND_CONSOLE);
+}
+
static bool exec_context_needs_term(const ExecContext *c) {
assert(c);
@@ -278,7 +293,7 @@ static int open_null_as(int flags, int nfd) {
}
static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
- union sockaddr_union sa = {
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
@@ -286,36 +301,32 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
gid_t oldgid = GID_INVALID;
int r;
- if (gid != GID_INVALID) {
+ if (gid_is_valid(gid)) {
oldgid = getgid();
- r = setegid(gid);
- if (r < 0)
+ if (setegid(gid) < 0)
return -errno;
}
- if (uid != UID_INVALID) {
+ if (uid_is_valid(uid)) {
olduid = getuid();
- r = seteuid(uid);
- if (r < 0) {
+ if (seteuid(uid) < 0) {
r = -errno;
goto restore_gid;
}
}
- r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
- if (r < 0)
- r = -errno;
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0 ? -errno : 0;
/* If we fail to restore the uid or gid, things will likely
fail later on. This should only happen if an LSM interferes. */
- if (uid != UID_INVALID)
+ if (uid_is_valid(uid))
(void) seteuid(olduid);
restore_gid:
- if (gid != GID_INVALID)
+ if (gid_is_valid(gid))
(void) setegid(oldgid);
return r;
@@ -324,6 +335,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
static int connect_logger_as(
Unit *unit,
const ExecContext *context,
+ const ExecParameters *params,
ExecOutput output,
const char *ident,
int nfd,
@@ -333,6 +345,7 @@ static int connect_logger_as(
int fd, r;
assert(context);
+ assert(params);
assert(output < _EXEC_OUTPUT_MAX);
assert(ident);
assert(nfd >= 0);
@@ -360,12 +373,12 @@ static int connect_logger_as(
"%i\n"
"%i\n"
"%i\n",
- context->syslog_identifier ? context->syslog_identifier : ident,
- unit->id,
+ context->syslog_identifier ?: ident,
+ params->flags & EXEC_PASS_LOG_UNIT ? unit->id : "",
context->syslog_priority,
!!context->syslog_level_prefix,
- output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
- output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
+ is_syslog_output(output),
+ is_kmsg_output(output),
is_terminal_output(output));
if (fd == nfd)
@@ -575,18 +588,22 @@ static int setup_output(
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- r = connect_logger_as(unit, context, o, ident, fileno, uid, gid);
+ r = connect_logger_as(unit, context, params, o, ident, fileno, uid, gid);
if (r < 0) {
- log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
+ log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
r = open_null_as(O_WRONLY, fileno);
} else {
struct stat st;
/* If we connected this fd to the journal via a stream, patch the device/inode into the passed
* parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits
- * services to detect whether they are connected to the journal or not. */
+ * services to detect whether they are connected to the journal or not.
+ *
+ * If both stdout and stderr are connected to a stream then let's make sure to store the data
+ * about STDERR as that's usually the best way to do logging. */
- if (fstat(fileno, &st) >= 0) {
+ if (fstat(fileno, &st) >= 0 &&
+ (*journal_stream_ino == 0 || fileno == STDERR_FILENO)) {
*journal_stream_dev = st.st_dev;
*journal_stream_ino = st.st_ino;
}
@@ -878,7 +895,7 @@ static int get_supplementary_groups(const ExecContext *c, const char *user,
keep_groups = true;
}
- if (!c->supplementary_groups)
+ if (strv_isempty(c->supplementary_groups))
return 0;
/*
@@ -952,7 +969,7 @@ static int enforce_groups(const ExecContext *context, gid_t gid,
assert(context);
/* Handle SupplementaryGroups= even if it is empty */
- if (context->supplementary_groups) {
+ if (!strv_isempty(context->supplementary_groups)) {
r = maybe_setgroups(ngids, supplementary_gids);
if (r < 0)
return r;
@@ -1023,7 +1040,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
return 0;
}
-#ifdef HAVE_PAM
+#if HAVE_PAM
static int null_conv(
int num_msg,
@@ -1047,7 +1064,7 @@ static int setup_pam(
char ***env,
int fds[], unsigned n_fds) {
-#ifdef HAVE_PAM
+#if HAVE_PAM
static const struct pam_conv conv = {
.conv = null_conv,
@@ -1120,7 +1137,7 @@ static int setup_pam(
assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0);
- parent_pid = getpid();
+ parent_pid = getpid_cached();
pam_pid = fork();
if (pam_pid < 0) {
@@ -1318,24 +1335,24 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
c->protect_kernel_modules ||
c->private_devices ||
context_has_syscall_filters(c) ||
- !set_isempty(c->syscall_archs);
+ !set_isempty(c->syscall_archs) ||
+ c->lock_personality;
}
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
static bool skip_seccomp_unavailable(const Unit* u, const char* msg) {
if (is_seccomp_available())
return false;
- log_open();
log_unit_debug(u, "SECCOMP features not detected in the kernel, skipping %s", msg);
- log_close();
return true;
}
-static int apply_syscall_filter(const Unit* u, const ExecContext *c) {
+static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_ambient_hack) {
uint32_t negative_action, default_action, action;
+ int r;
assert(u);
assert(c);
@@ -1356,6 +1373,12 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c) {
action = negative_action;
}
+ if (needs_ambient_hack) {
+ r = seccomp_filter_set_add(c->syscall_filter, c->syscall_whitelist, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
+ if (r < 0)
+ return r;
+ }
+
return seccomp_load_syscall_filter_set_raw(default_action, c->syscall_filter, action);
}
@@ -1470,6 +1493,32 @@ static int apply_restrict_namespaces(Unit *u, const ExecContext *c) {
return seccomp_restrict_namespaces(c->restrict_namespaces);
}
+static int apply_lock_personality(const Unit* u, const ExecContext *c) {
+ unsigned long personality;
+ int r;
+
+ assert(u);
+ assert(c);
+
+ if (!c->lock_personality)
+ return 0;
+
+ if (skip_seccomp_unavailable(u, "LockPersonality="))
+ return 0;
+
+ personality = c->personality;
+
+ /* If personality is not specified, use either PER_LINUX or PER_LINUX32 depending on what is currently set. */
+ if (personality == PERSONALITY_INVALID) {
+
+ r = opinionated_personality(&personality);
+ if (r < 0)
+ return r;
+ }
+
+ return seccomp_lock_personality(personality);
+}
+
#endif
static void do_idle_pipe_dance(int idle_pipe[4]) {
@@ -1527,7 +1576,7 @@ static int build_environment(
if (n_fds > 0) {
_cleanup_free_ char *joined = NULL;
- if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
+ if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid_cached()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1546,7 +1595,7 @@ static int build_environment(
}
if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
- if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
+ if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid_cached()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1558,7 +1607,7 @@ static int build_environment(
/* If this is D-Bus, tell the nss-systemd module, since it relies on being able to use D-Bus look up dynamic
* users via PID 1, possibly dead-locking the dbus daemon. This way it will not use D-Bus to resolve names, but
* check the database directly. */
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE)) {
+ if (p->flags & EXEC_NSS_BYPASS_BUS) {
x = strdup("SYSTEMD_NSS_BYPASS_BUS=1");
if (!x)
return -ENOMEM;
@@ -1649,8 +1698,10 @@ static int build_pass_environment(const ExecContext *c, char ***ret) {
x = strjoin(*i, "=", v);
if (!x)
return -ENOMEM;
+
if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
return -ENOMEM;
+
pass_env[n_env++] = x;
pass_env[n_env] = NULL;
x = NULL;
@@ -1698,6 +1749,13 @@ static bool exec_needs_mount_namespace(
if (context->mount_apivfs && (context->root_image || context->root_directory))
return true;
+ if (context->dynamic_user &&
+ (!strv_isempty(context->directories[EXEC_DIRECTORY_RUNTIME].paths) ||
+ !strv_isempty(context->directories[EXEC_DIRECTORY_STATE].paths) ||
+ !strv_isempty(context->directories[EXEC_DIRECTORY_CACHE].paths) ||
+ !strv_isempty(context->directories[EXEC_DIRECTORY_LOGS].paths)))
+ return true;
+
return false;
}
@@ -1860,50 +1918,161 @@ static int setup_private_users(uid_t uid, gid_t gid) {
return 0;
}
-static int setup_runtime_directory(
+static int setup_exec_directory(
const ExecContext *context,
const ExecParameters *params,
uid_t uid,
- gid_t gid) {
+ gid_t gid,
+ ExecDirectoryType type,
+ int *exit_status) {
+ static const int exit_status_table[_EXEC_DIRECTORY_TYPE_MAX] = {
+ [EXEC_DIRECTORY_RUNTIME] = EXIT_RUNTIME_DIRECTORY,
+ [EXEC_DIRECTORY_STATE] = EXIT_STATE_DIRECTORY,
+ [EXEC_DIRECTORY_CACHE] = EXIT_CACHE_DIRECTORY,
+ [EXEC_DIRECTORY_LOGS] = EXIT_LOGS_DIRECTORY,
+ [EXEC_DIRECTORY_CONFIGURATION] = EXIT_CONFIGURATION_DIRECTORY,
+ };
char **rt;
int r;
assert(context);
assert(params);
+ assert(type >= 0 && type < _EXEC_DIRECTORY_TYPE_MAX);
+ assert(exit_status);
- STRV_FOREACH(rt, context->runtime_directory) {
- _cleanup_free_ char *p;
+ if (!params->prefix[type])
+ return 0;
- p = strjoin(params->runtime_prefix, "/", *rt);
- if (!p)
- return -ENOMEM;
+ if (params->flags & EXEC_CHOWN_DIRECTORIES) {
+ if (!uid_is_valid(uid))
+ uid = 0;
+ if (!gid_is_valid(gid))
+ gid = 0;
+ }
+
+ STRV_FOREACH(rt, context->directories[type].paths) {
+ _cleanup_free_ char *p = NULL, *pp = NULL;
+ const char *effective;
+
+ p = strjoin(params->prefix[type], "/", *rt);
+ if (!p) {
+ r = -ENOMEM;
+ goto fail;
+ }
- r = mkdir_p_label(p, context->runtime_directory_mode);
+ r = mkdir_parents_label(p, 0755);
if (r < 0)
- return r;
+ goto fail;
+
+ if (context->dynamic_user && type != EXEC_DIRECTORY_CONFIGURATION) {
+ _cleanup_free_ char *private_root = NULL, *relative = NULL, *parent = NULL;
+
+ /* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
+ * want to avoid leaving a directory around fully accessible that is owned by a dynamic user
+ * whose UID is later on reused. To lock this down we use the same trick used by container
+ * managers to prohibit host users to get access to files of the same UID in containers: we
+ * place everything inside a directory that has an access mode of 0700 and is owned root:root,
+ * so that it acts as security boundary for unprivileged host code. We then use fs namespacing
+ * to make this directory permeable for the service itself.
+ *
+ * Specifically: for a service which wants a special directory "foo/" we first create a
+ * directory "private/" with access mode 0700 owned by root:root. Then we place "foo" inside of
+ * that directory (i.e. "private/foo/"), and make "foo" a symlink to "private/foo". This way,
+ * privileged host users can access "foo/" as usual, but unprivileged host users can't look
+ * into it. Inside of the namespaceof the container "private/" is replaced by a more liberally
+ * accessible tmpfs, into which the host's "private/foo/" is mounted under the same name, thus
+ * disabling the access boundary for the service and making sure it only gets access to the
+ * dirs it needs but no others. Tricky? Yes, absolutely, but it works!
+ *
+ * Note that we don't do this for EXEC_DIRECTORY_CONFIGURATION as that's assumed not to be
+ * owned by the service itself. */
+
+ private_root = strjoin(params->prefix[type], "/private");
+ if (!private_root) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* First set up private root if it doesn't exist yet, with access mode 0700 and owned by root:root */
+ r = mkdir_safe_label(private_root, 0700, 0, 0);
+ if (r < 0)
+ goto fail;
+
+ pp = strjoin(private_root, "/", *rt);
+ if (!pp) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ /* Create all directories between the configured directory and this private root, and mark them 0755 */
+ r = mkdir_parents_label(pp, 0755);
+ if (r < 0)
+ goto fail;
+
+ /* Finally, create the actual directory for the service */
+ r = mkdir_label(pp, context->directories[type].mode);
+ if (r < 0 && r != -EEXIST)
+ goto fail;
+
+ parent = dirname_malloc(p);
+ if (!parent) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ r = path_make_relative(parent, pp, &relative);
+ if (r < 0)
+ goto fail;
+
+ /* And link it up from the original place */
+ r = symlink_idempotent(relative, p);
+ if (r < 0)
+ goto fail;
+
+ effective = pp;
+
+ } else {
+ r = mkdir_label(p, context->directories[type].mode);
+ if (r < 0 && r != -EEXIST)
+ goto fail;
+
+ effective = p;
+ }
+
+ /* First lock down the access mode */
+ if (chmod(effective, context->directories[type].mode) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ /* Don't change the owner of the configuration directory, as in the common case it is not written to by
+ * a service, and shall not be writable. */
+ if (type == EXEC_DIRECTORY_CONFIGURATION)
+ continue;
- r = chmod_and_chown(p, context->runtime_directory_mode, uid, gid);
+ /* Then, change the ownership of the whole tree, if necessary */
+ r = path_chown_recursive(effective, uid, gid);
if (r < 0)
- return r;
+ goto fail;
}
return 0;
+
+fail:
+ *exit_status = exit_status_table[type];
+ return r;
}
static int setup_smack(
const ExecContext *context,
const ExecCommand *command) {
-#ifdef HAVE_SMACK
int r;
assert(context);
assert(command);
- if (!mac_smack_use())
- return 0;
-
if (context->smack_process_label) {
r = mac_smack_apply_pid(0, context->smack_process_label);
if (r < 0)
@@ -1914,7 +2083,7 @@ static int setup_smack(
_cleanup_free_ char *exec_label = NULL;
r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
- if (r < 0 && r != -ENODATA && r != -EOPNOTSUPP)
+ if (r < 0 && !IN_SET(r, -ENODATA, -EOPNOTSUPP))
return r;
r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
@@ -1922,7 +2091,6 @@ static int setup_smack(
return r;
}
#endif
-#endif
return 0;
}
@@ -1934,29 +2102,40 @@ static int compile_read_write_paths(
_cleanup_strv_free_ char **l = NULL;
char **rt;
+ ExecDirectoryType i;
/* Compile the list of writable paths. This is the combination of
* the explicitly configured paths, plus all runtime directories. */
- if (strv_isempty(context->read_write_paths) &&
- strv_isempty(context->runtime_directory)) {
- *ret = NULL; /* NOP if neither is set */
- return 0;
+ if (strv_isempty(context->read_write_paths)) {
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
+ if (!strv_isempty(context->directories[i].paths))
+ break;
+
+ if (i == _EXEC_DIRECTORY_TYPE_MAX) {
+ *ret = NULL; /* NOP if neither is set */
+ return 0;
+ }
}
l = strv_copy(context->read_write_paths);
if (!l)
return -ENOMEM;
- STRV_FOREACH(rt, context->runtime_directory) {
- char *s;
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
+ if (!params->prefix[i])
+ continue;
- s = strjoin(params->runtime_prefix, "/", *rt);
- if (!s)
- return -ENOMEM;
+ STRV_FOREACH(rt, context->directories[i].paths) {
+ char *s;
- if (strv_consume(&l, s) < 0)
- return -ENOMEM;
+ s = strjoin(params->prefix[i], "/", *rt);
+ if (!s)
+ return -ENOMEM;
+
+ if (strv_consume(&l, s) < 0)
+ return -ENOMEM;
+ }
}
*ret = l;
@@ -1965,6 +2144,143 @@ static int compile_read_write_paths(
return 0;
}
+static int compile_bind_mounts(
+ const ExecContext *context,
+ const ExecParameters *params,
+ BindMount **ret_bind_mounts,
+ unsigned *ret_n_bind_mounts,
+ char ***ret_empty_directories) {
+
+ _cleanup_strv_free_ char **empty_directories = NULL;
+ BindMount *bind_mounts;
+ unsigned n, h = 0, i;
+ ExecDirectoryType t;
+ int r;
+
+ assert(context);
+ assert(params);
+ assert(ret_bind_mounts);
+ assert(ret_n_bind_mounts);
+ assert(ret_empty_directories);
+
+ n = context->n_bind_mounts;
+ for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+ if (!params->prefix[t])
+ continue;
+
+ n += strv_length(context->directories[t].paths);
+ }
+
+ if (n <= 0) {
+ *ret_bind_mounts = NULL;
+ *ret_n_bind_mounts = 0;
+ *ret_empty_directories = NULL;
+ return 0;
+ }
+
+ bind_mounts = new(BindMount, n);
+ if (!bind_mounts)
+ return -ENOMEM;
+
+ for (i = 0; context->n_bind_mounts; i++) {
+ BindMount *item = context->bind_mounts + i;
+ char *s, *d;
+
+ s = strdup(item->source);
+ if (!s) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ d = strdup(item->destination);
+ if (!d) {
+ free(s);
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ bind_mounts[h++] = (BindMount) {
+ .source = s,
+ .destination = d,
+ .read_only = item->read_only,
+ .recursive = item->recursive,
+ .ignore_enoent = item->ignore_enoent,
+ };
+ }
+
+ for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+ char **suffix;
+
+ if (!params->prefix[t])
+ continue;
+
+ if (strv_isempty(context->directories[t].paths))
+ continue;
+
+ if (context->dynamic_user && t != EXEC_DIRECTORY_CONFIGURATION) {
+ char *private_root;
+
+ /* So this is for a dynamic user, and we need to make sure the process can access its own
+ * directory. For that we overmount the usually inaccessible "private" subdirectory with a
+ * tmpfs that makes it accessible and is empty except for the submounts we do this for. */
+
+ private_root = strjoin(params->prefix[t], "/private");
+ if (!private_root) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ r = strv_consume(&empty_directories, private_root);
+ if (r < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+ }
+
+ STRV_FOREACH(suffix, context->directories[t].paths) {
+ char *s, *d;
+
+ if (context->dynamic_user && t != EXEC_DIRECTORY_CONFIGURATION)
+ s = strjoin(params->prefix[t], "/private/", *suffix);
+ else
+ s = strjoin(params->prefix[t], "/", *suffix);
+ if (!s) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ d = strdup(s);
+ if (!d) {
+ free(s);
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ bind_mounts[h++] = (BindMount) {
+ .source = s,
+ .destination = d,
+ .read_only = false,
+ .recursive = true,
+ .ignore_enoent = false,
+ };
+ }
+ }
+
+ assert(h == n);
+
+ *ret_bind_mounts = bind_mounts;
+ *ret_n_bind_mounts = n;
+ *ret_empty_directories = empty_directories;
+
+ empty_directories = NULL;
+
+ return (int) n;
+
+finish:
+ bind_mount_free_many(bind_mounts, h);
+ return r;
+}
+
static int apply_mount_namespace(
Unit *u,
ExecCommand *command,
@@ -1972,7 +2288,7 @@ static int apply_mount_namespace(
const ExecParameters *params,
ExecRuntime *runtime) {
- _cleanup_strv_free_ char **rw = NULL;
+ _cleanup_strv_free_ char **rw = NULL, **empty_directories = NULL;
char *tmp = NULL, *var = NULL;
const char *root_dir = NULL, *root_image = NULL;
NameSpaceInfo ns_info = {
@@ -1983,7 +2299,9 @@ static int apply_mount_namespace(
.protect_kernel_modules = context->protect_kernel_modules,
.mount_apivfs = context->mount_apivfs,
};
- bool apply_restrictions;
+ bool needs_sandboxing;
+ BindMount *bind_mounts = NULL;
+ unsigned n_bind_mounts = 0;
int r;
assert(context);
@@ -2010,6 +2328,10 @@ static int apply_mount_namespace(
root_dir = context->root_directory;
}
+ r = compile_bind_mounts(context, params, &bind_mounts, &n_bind_mounts, &empty_directories);
+ if (r < 0)
+ return r;
+
/*
* If DynamicUser=no and RootDirectory= is set then lets pass a relaxed
* sandbox info, otherwise enforce it, don't ignore protected paths and
@@ -2018,28 +2340,29 @@ static int apply_mount_namespace(
if (!context->dynamic_user && root_dir)
ns_info.ignore_protect_paths = true;
- apply_restrictions = (params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged;
+ needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
r = setup_namespace(root_dir, root_image,
&ns_info, rw,
- apply_restrictions ? context->read_only_paths : NULL,
- apply_restrictions ? context->inaccessible_paths : NULL,
- context->bind_mounts,
- context->n_bind_mounts,
+ needs_sandboxing ? context->read_only_paths : NULL,
+ needs_sandboxing ? context->inaccessible_paths : NULL,
+ empty_directories,
+ bind_mounts,
+ n_bind_mounts,
tmp,
var,
- apply_restrictions ? context->protect_home : PROTECT_HOME_NO,
- apply_restrictions ? context->protect_system : PROTECT_SYSTEM_NO,
+ needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
+ needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
DISSECT_IMAGE_DISCARD_ON_LOOP);
+ bind_mount_free_many(bind_mounts, n_bind_mounts);
+
/* If we couldn't set up the namespace this is probably due to a
* missing capability. In this case, silently proceeed. */
if (IN_SET(r, -EPERM, -EACCES)) {
- log_open();
log_unit_debug_errno(u, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
- log_close();
- r = 0;
+ return 0;
}
return r;
@@ -2090,10 +2413,17 @@ static int apply_working_directory(
return 0;
}
-static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid) {
+static int setup_keyring(
+ Unit *u,
+ const ExecContext *context,
+ const ExecParameters *p,
+ uid_t uid, gid_t gid) {
+
key_serial_t keyring;
+ int r;
assert(u);
+ assert(context);
assert(p);
/* Let's set up a new per-service "session" kernel keyring for each system service. This has the benefit that
@@ -2106,16 +2436,19 @@ static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid)
if (!(p->flags & EXEC_NEW_KEYRING))
return 0;
+ if (context->keyring_mode == EXEC_KEYRING_INHERIT)
+ return 0;
+
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
if (keyring == -1) {
if (errno == ENOSYS)
- log_debug_errno(errno, "Kernel keyring not supported, ignoring.");
+ log_unit_debug_errno(u, errno, "Kernel keyring not supported, ignoring.");
else if (IN_SET(errno, EACCES, EPERM))
- log_debug_errno(errno, "Kernel keyring access prohibited, ignoring.");
+ log_unit_debug_errno(u, errno, "Kernel keyring access prohibited, ignoring.");
else if (errno == EDQUOT)
- log_debug_errno(errno, "Out of kernel keyrings to allocate, ignoring.");
+ log_unit_debug_errno(u, errno, "Out of kernel keyrings to allocate, ignoring.");
else
- return log_error_errno(errno, "Setting up kernel keyring failed: %m");
+ return log_unit_error_errno(u, errno, "Setting up kernel keyring failed: %m");
return 0;
}
@@ -2126,19 +2459,68 @@ static int setup_keyring(Unit *u, const ExecParameters *p, uid_t uid, gid_t gid)
key = add_key("user", "invocation_id", &u->invocation_id, sizeof(u->invocation_id), KEY_SPEC_SESSION_KEYRING);
if (key == -1)
- log_debug_errno(errno, "Failed to add invocation ID to keyring, ignoring: %m");
+ log_unit_debug_errno(u, errno, "Failed to add invocation ID to keyring, ignoring: %m");
else {
if (keyctl(KEYCTL_SETPERM, key,
KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH|
KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH, 0, 0) < 0)
- return log_error_errno(errno, "Failed to restrict invocation ID permission: %m");
+ return log_unit_error_errno(u, errno, "Failed to restrict invocation ID permission: %m");
}
}
/* And now, make the keyring owned by the service's user */
if (uid_is_valid(uid) || gid_is_valid(gid))
if (keyctl(KEYCTL_CHOWN, keyring, uid, gid, 0) < 0)
- return log_error_errno(errno, "Failed to change ownership of session keyring: %m");
+ return log_unit_error_errno(u, errno, "Failed to change ownership of session keyring: %m");
+
+ /* When requested link the user keyring into the session keyring. */
+ if (context->keyring_mode == EXEC_KEYRING_SHARED) {
+ uid_t saved_uid;
+ gid_t saved_gid;
+
+ /* Acquiring a reference to the user keyring is nasty. We briefly change identity in order to get things
+ * set up properly by the kernel. If we don't do that then we can't create it atomically, and that
+ * sucks for parallel execution. This mimics what pam_keyinit does, too.*/
+
+ saved_uid = getuid();
+ saved_gid = getgid();
+
+ if (gid_is_valid(gid) && gid != saved_gid) {
+ if (setregid(gid, -1) < 0)
+ return log_unit_error_errno(u, errno, "Failed to change GID for user keyring: %m");
+ }
+
+ if (uid_is_valid(uid) && uid != saved_uid) {
+ if (setreuid(uid, -1) < 0) {
+ (void) setregid(saved_gid, -1);
+ return log_unit_error_errno(u, errno, "Failed to change UID for user keyring: %m");
+ }
+ }
+
+ if (keyctl(KEYCTL_LINK,
+ KEY_SPEC_USER_KEYRING,
+ KEY_SPEC_SESSION_KEYRING, 0, 0) < 0) {
+
+ r = -errno;
+
+ (void) setreuid(saved_uid, -1);
+ (void) setregid(saved_gid, -1);
+
+ return log_unit_error_errno(u, r, "Failed to link user keyring into session keyring: %m");
+ }
+
+ if (uid_is_valid(uid) && uid != saved_uid) {
+ if (setreuid(saved_uid, -1) < 0) {
+ (void) setregid(saved_gid, -1);
+ return log_unit_error_errno(u, errno, "Failed to change UID back for user keyring: %m");
+ }
+ }
+
+ if (gid_is_valid(gid) && gid != saved_gid) {
+ if (setregid(saved_gid, -1) < 0)
+ return log_unit_error_errno(u, errno, "Failed to change GID back for user keyring: %m");
+ }
+ }
return 0;
}
@@ -2219,9 +2601,9 @@ static int send_user_lookup(
if (writev(user_lookup_fd,
(struct iovec[]) {
- { .iov_base = &uid, .iov_len = sizeof(uid) },
- { .iov_base = &gid, .iov_len = sizeof(gid) },
- { .iov_base = unit->id, .iov_len = strlen(unit->id) }}, 3) < 0)
+ IOVEC_INIT(&uid, sizeof(uid)),
+ IOVEC_INIT(&gid, sizeof(gid)),
+ IOVEC_INIT_STRING(unit->id) }, 3) < 0)
return -errno;
return 0;
@@ -2256,6 +2638,49 @@ static int acquire_home(const ExecContext *c, uid_t uid, const char** home, char
return 1;
}
+static int compile_suggested_paths(const ExecContext *c, const ExecParameters *p, char ***ret) {
+ _cleanup_strv_free_ char ** list = NULL;
+ ExecDirectoryType t;
+ int r;
+
+ assert(c);
+ assert(p);
+ assert(ret);
+
+ assert(c->dynamic_user);
+
+ /* Compile a list of paths that it might make sense to read the owning UID from to use as initial candidate for
+ * dynamic UID allocation, in order to save us from doing costly recursive chown()s of the special
+ * directories. */
+
+ for (t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
+ char **i;
+
+ if (t == EXEC_DIRECTORY_CONFIGURATION)
+ continue;
+
+ if (!p->prefix[t])
+ continue;
+
+ STRV_FOREACH(i, c->directories[t].paths) {
+ char *e;
+
+ e = strjoin(p->prefix[t], "/private/", *i);
+ if (!e)
+ return -ENOMEM;
+
+ r = strv_consume(&list, e);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ *ret = list;
+ list = NULL;
+
+ return 0;
+}
+
static int exec_child(
Unit *unit,
ExecCommand *command,
@@ -2271,8 +2696,7 @@ static int exec_child(
unsigned n_socket_fds,
char **files_env,
int user_lookup_fd,
- int *exit_status,
- char **error_message) {
+ int *exit_status) {
_cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL, *home_buffer = NULL;
@@ -2281,20 +2705,31 @@ static int exec_child(
const char *home = NULL, *shell = NULL;
dev_t journal_stream_dev = 0;
ino_t journal_stream_ino = 0;
- bool needs_mount_namespace;
+ bool needs_sandboxing, /* Do we need to set up full sandboxing? (i.e. all namespacing, all MAC stuff, caps, yadda yadda */
+ needs_setuid, /* Do we need to do the actual setresuid()/setresgid() calls? */
+ needs_mount_namespace, /* Do we need to set up a mount namespace for this kernel? */
+ needs_ambient_hack; /* Do we need to apply the ambient capabilities hack? */
+#if HAVE_SELINUX
+ bool use_selinux = false;
+#endif
+#if ENABLE_SMACK
+ bool use_smack = false;
+#endif
+#if HAVE_APPARMOR
+ bool use_apparmor = false;
+#endif
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r, ngids = 0;
unsigned n_fds;
+ ExecDirectoryType dt;
+ int secure_bits;
assert(unit);
assert(command);
assert(context);
assert(params);
assert(exit_status);
- assert(error_message);
- /* We don't always set error_message, hence it must be initialized */
- assert(*error_message == NULL);
rename_process_from_path(command->path);
@@ -2312,32 +2747,34 @@ static int exec_child(
r = reset_signal_mask();
if (r < 0) {
*exit_status = EXIT_SIGNAL_MASK;
- *error_message = strdup("Failed to reset signal mask");
- /* If strdup fails, here and below, we will just print the generic error message. */
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set process signal mask: %m");
}
if (params->idle_pipe)
do_idle_pipe_dance(params->idle_pipe);
- /* Close sockets very early to make sure we don't
- * block init reexecution because it cannot bind its
- * sockets */
+ /* Close fds we don't need very early to make sure we don't block init reexecution because it cannot bind its
+ * sockets. Among the fds we close are the logging fds, and we want to keep them closed, so that we don't have
+ * any fds open we don't really want open during the transition. In order to make logging work, we switch the
+ * log subsystem into open_when_needed mode, so that it reopens the logs on every single log call. */
log_forget_fds();
+ log_set_open_when_needed(true);
+
+ /* In case anything used libc syslog(), close this here, too */
+ closelog();
n_fds = n_storage_fds + n_socket_fds;
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
- *error_message = strdup("Failed to close remaining fds");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m");
}
if (!context->same_pgrp)
if (setsid() < 0) {
*exit_status = EXIT_SETSID;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to create new process session: %m");
}
exec_context_tty_reset(context, params);
@@ -2348,8 +2785,8 @@ static int exec_child(
cmdline = exec_command_line(argv);
if (!cmdline) {
- *exit_status = EXIT_CONFIRM;
- return -ENOMEM;
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
}
r = ask_for_confirmation(vc, unit, cmdline);
@@ -2359,37 +2796,41 @@ static int exec_child(
return 0;
}
*exit_status = EXIT_CONFIRM;
- *error_message = strdup("Execution cancelled");
+ log_unit_error(unit, "Execution cancelled by the user");
return -ECANCELED;
}
}
if (context->dynamic_user && dcreds) {
+ _cleanup_strv_free_ char **suggested_paths = NULL;
/* Make sure we bypass our own NSS module for any NSS checks */
if (putenv((char*) "SYSTEMD_NSS_DYNAMIC_BYPASS=1") != 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to update environment");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to update environment: %m");
+ }
+
+ r = compile_suggested_paths(context, params, &suggested_paths);
+ if (r < 0) {
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
}
- r = dynamic_creds_realize(dcreds, &uid, &gid);
+ r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to update dynamic user credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m");
}
if (!uid_is_valid(uid)) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "UID validation failed for \""UID_FMT"\"", uid);
- /* If asprintf fails, here and below, we will just print the generic error message. */
+ log_unit_error(unit, "UID validation failed for \""UID_FMT"\"", uid);
return -ESRCH;
}
if (!gid_is_valid(gid)) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "GID validation failed for \""GID_FMT"\"", gid);
+ log_unit_error(unit, "GID validation failed for \""GID_FMT"\"", gid);
return -ESRCH;
}
@@ -2400,15 +2841,13 @@ static int exec_child(
r = get_fixed_user(context, &username, &uid, &gid, &home, &shell);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to determine user credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine user credentials: %m");
}
r = get_fixed_group(context, &groupname, &gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
- *error_message = strdup("Failed to determine group credentials");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine group credentials: %m");
}
}
@@ -2417,15 +2856,13 @@ static int exec_child(
&supplementary_gids, &ngids);
if (r < 0) {
*exit_status = EXIT_GROUP;
- *error_message = strdup("Failed to determine supplementary groups");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine supplementary groups: %m");
}
r = send_user_lookup(unit, user_lookup_fd, uid, gid);
if (r < 0) {
*exit_status = EXIT_USER;
- *error_message = strdup("Failed to send user credentials to PID1");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to send user credentials to PID1: %m");
}
user_lookup_fd = safe_close(user_lookup_fd);
@@ -2433,8 +2870,7 @@ static int exec_child(
r = acquire_home(context, uid, &home, &home_buffer);
if (r < 0) {
*exit_status = EXIT_CHDIR;
- *error_message = strdup("Failed to determine $HOME for user");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to determine $HOME for user: %m");
}
/* If a socket is connected to STDIN/STDOUT/STDERR, we
@@ -2445,30 +2881,26 @@ static int exec_child(
r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
- *error_message = strdup("Failed to set up stdin");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard input: %m");
}
r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
- *error_message = strdup("Failed to set up stdout");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard output: %m");
}
r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
- *error_message = strdup("Failed to set up stderr");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up standard error output: %m");
}
if (params->cgroup_path) {
r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- (void) asprintf(error_message, "Failed to attach to cgroup %s", params->cgroup_path);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to attach to cgroup %s: %m", params->cgroup_path);
}
}
@@ -2482,21 +2914,18 @@ static int exec_child(
sprintf(t, "%i", context->oom_score_adjust);
r = write_string_file("/proc/self/oom_score_adj", t, 0);
- if (r == -EPERM || r == -EACCES) {
- log_open();
+ if (IN_SET(r, -EPERM, -EACCES))
log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
- log_close();
- } else if (r < 0) {
+ else if (r < 0) {
*exit_status = EXIT_OOM_ADJUST;
- *error_message = strdup("Failed to write /proc/self/oom_score_adj");
- return -errno;
+ return log_unit_error_errno(unit, r, "Failed to adjust OOM setting: %m");
}
}
if (context->nice_set)
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
*exit_status = EXIT_NICE;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up process scheduling priority (nice level): %m");
}
if (context->cpu_sched_set) {
@@ -2511,36 +2940,38 @@ static int exec_child(
&param);
if (r < 0) {
*exit_status = EXIT_SETSCHEDULER;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up CPU scheduling: %m");
}
}
if (context->cpuset)
if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
*exit_status = EXIT_CPUAFFINITY;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up CPU affinity: %m");
}
if (context->ioprio_set)
if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
*exit_status = EXIT_IOPRIO;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up IO scheduling priority: %m");
}
if (context->timer_slack_nsec != NSEC_INFINITY)
if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
*exit_status = EXIT_TIMERSLACK;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set up timer slack: %m");
}
- if (context->personality != PERSONALITY_INVALID)
- if (personality(context->personality) < 0) {
+ if (context->personality != PERSONALITY_INVALID) {
+ r = safe_personality(context->personality);
+ if (r < 0) {
*exit_status = EXIT_PERSONALITY;
- return -errno;
+ return log_unit_error_errno(unit, r, "Failed to set up execution domain (personality): %m");
}
+ }
if (context->utmp_id)
- utmp_put_init_process(context->utmp_id, getpid(), getsid(0),
+ utmp_put_init_process(context->utmp_id, getpid_cached(), getsid(0),
context->tty_path,
context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS :
context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS :
@@ -2551,34 +2982,31 @@ static int exec_child(
r = chown_terminal(STDIN_FILENO, uid);
if (r < 0) {
*exit_status = EXIT_STDIN;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change ownership of terminal: %m");
}
}
/* If delegation is enabled we'll pass ownership of the cgroup
* (but only in systemd's own controller hierarchy!) to the
* user of the new process. */
- if (params->cgroup_path && context->user && params->cgroup_delegate) {
+ if (params->cgroup_path && context->user && (params->flags & EXEC_CGROUP_DELEGATE)) {
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
}
-
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
}
}
- if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
- r = setup_runtime_directory(context, params, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_RUNTIME_DIRECTORY;
- return r;
- }
+ for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
+ r = setup_exec_directory(context, params, uid, gid, dt, exit_status);
+ if (r < 0)
+ return log_unit_error_errno(unit, r, "Failed to set up special execution directory in %s: %m", params->prefix[dt]);
}
r = build_environment(
@@ -2594,13 +3022,13 @@ static int exec_child(
&our_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
- return r;
+ return log_oom();
}
r = build_pass_environment(context, &pass_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
- return r;
+ return log_oom();
}
accum_env = strv_env_merge(5,
@@ -2612,24 +3040,52 @@ static int exec_child(
NULL);
if (!accum_env) {
*exit_status = EXIT_MEMORY;
- return -ENOMEM;
+ return log_oom();
}
accum_env = strv_env_clean(accum_env);
(void) umask(context->umask);
- r = setup_keyring(unit, params, uid, gid);
+ r = setup_keyring(unit, context, params, uid, gid);
if (r < 0) {
*exit_status = EXIT_KEYRING;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up kernel keyring: %m");
}
- if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
+ /* We need sandboxing if the caller asked us to apply it and the command isn't explicitly excepted from it */
+ needs_sandboxing = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & EXEC_COMMAND_FULLY_PRIVILEGED);
+
+ /* We need the ambient capability hack, if the caller asked us to apply it and the command is marked for it, and the kernel doesn't actually support ambient caps */
+ needs_ambient_hack = (params->flags & EXEC_APPLY_SANDBOXING) && (command->flags & EXEC_COMMAND_AMBIENT_MAGIC) && !ambient_capabilities_supported();
+
+ /* We need setresuid() if the caller asked us to apply sandboxing and the command isn't explicitly excepted from either whole sandboxing or just setresuid() itself, and the ambient hack is not desired */
+ if (needs_ambient_hack)
+ needs_setuid = false;
+ else
+ needs_setuid = (params->flags & EXEC_APPLY_SANDBOXING) && !(command->flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID));
+
+ if (needs_sandboxing) {
+ /* MAC enablement checks need to be done before a new mount ns is created, as they rely on /sys being
+ * present. The actual MAC context application will happen later, as late as possible, to avoid
+ * impacting our own code paths. */
+
+#if HAVE_SELINUX
+ use_selinux = mac_selinux_use();
+#endif
+#if ENABLE_SMACK
+ use_smack = mac_smack_use();
+#endif
+#if HAVE_APPARMOR
+ use_apparmor = mac_apparmor_use();
+#endif
+ }
+
+ if (needs_setuid) {
if (context->pam_name && username) {
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up PAM session: %m");
}
}
}
@@ -2638,7 +3094,7 @@ static int exec_child(
r = setup_netns(runtime->netns_storage_socket);
if (r < 0) {
*exit_status = EXIT_NETWORK;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up network namespacing: %m");
}
}
@@ -2647,53 +3103,47 @@ static int exec_child(
r = apply_mount_namespace(unit, command, context, params, runtime);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up mount namespacing: %m");
}
}
/* Apply just after mount namespace setup */
r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status);
if (r < 0)
- return r;
+ return log_unit_error_errno(unit, r, "Changing to the requested working directory failed: %m");
/* Drop groups as early as possbile */
- if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
+ if (needs_setuid) {
r = enforce_groups(context, gid, supplementary_gids, ngids);
if (r < 0) {
*exit_status = EXIT_GROUP;
- return r;
+ return log_unit_error_errno(unit, r, "Changing group credentials failed: %m");
}
}
-#ifdef HAVE_SELINUX
- if ((params->flags & EXEC_APPLY_PERMISSIONS) &&
- mac_selinux_use() &&
- params->selinux_context_net &&
- socket_fd >= 0 &&
- !command->privileged) {
-
- r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
- if (r < 0) {
- *exit_status = EXIT_SELINUX_CONTEXT;
- return r;
+ if (needs_sandboxing) {
+#if HAVE_SELINUX
+ if (use_selinux && params->selinux_context_net && socket_fd >= 0) {
+ r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
+ if (r < 0) {
+ *exit_status = EXIT_SELINUX_CONTEXT;
+ return log_unit_error_errno(unit, r, "Failed to determine SELinux context: %m");
+ }
}
- }
#endif
- if ((params->flags & EXEC_APPLY_PERMISSIONS) && context->private_users) {
- r = setup_private_users(uid, gid);
- if (r < 0) {
- *exit_status = EXIT_USER;
- return r;
+ if (context->private_users) {
+ r = setup_private_users(uid, gid);
+ if (r < 0) {
+ *exit_status = EXIT_USER;
+ return log_unit_error_errno(unit, r, "Failed to set up user namespacing: %m");
+ }
}
}
- /* We repeat the fd closing here, to make sure that
- * nothing is leaked from the PAM modules. Note that
- * we are more aggressive this time since socket_fd
- * and the netns fds we don't need anymore. The custom
- * endpoint fd was needed to upload the policy and can
- * now be closed as well. */
+ /* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
+ * more aggressive this time since socket_fd and the netns fds we don't need anymore. The custom endpoint fd
+ * was needed to upload the policy and can now be closed as well. */
r = close_all_fds(fds, n_fds);
if (r >= 0)
r = shift_fds(fds, n_fds);
@@ -2701,12 +3151,13 @@ static int exec_child(
r = flags_fds(fds, n_storage_fds, n_socket_fds, context->non_blocking);
if (r < 0) {
*exit_status = EXIT_FDS;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust passed file descriptors: %m");
}
- if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
+ secure_bits = context->secure_bits;
- int secure_bits = context->secure_bits;
+ if (needs_sandboxing) {
+ uint64_t bset;
for (i = 0; i < _RLIMIT_MAX; i++) {
@@ -2716,7 +3167,7 @@ static int exec_child(
r = setrlimit_closest(i, context->rlimit[i]);
if (r < 0) {
*exit_status = EXIT_LIMITS;
- return r;
+ return log_unit_error_errno(unit, r, "Failed to adjust resource limit %s: %m", rlimit_to_string(i));
}
}
@@ -2724,27 +3175,35 @@ static int exec_child(
if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) {
if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) {
*exit_status = EXIT_LIMITS;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to adjust RLIMIT_RTPRIO resource limit: %m");
}
}
- if (!cap_test_all(context->capability_bounding_set)) {
- r = capability_bounding_set_drop(context->capability_bounding_set, false);
+ bset = context->capability_bounding_set;
+ /* If the ambient caps hack is enabled (which means the kernel can't do them, and the user asked for
+ * our magic fallback), then let's add some extra caps, so that the service can drop privs of its own,
+ * instead of us doing that */
+ if (needs_ambient_hack)
+ bset |= (UINT64_C(1) << CAP_SETPCAP) |
+ (UINT64_C(1) << CAP_SETUID) |
+ (UINT64_C(1) << CAP_SETGID);
+
+ if (!cap_test_all(bset)) {
+ r = capability_bounding_set_drop(bset, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to drop capabilities");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to drop capabilities: %m");
}
}
/* This is done before enforce_user, but ambient set
* does not survive over setresuid() if keep_caps is not set. */
- if (context->capability_ambient_set != 0) {
+ if (!needs_ambient_hack &&
+ context->capability_ambient_set != 0) {
r = capability_ambient_set_apply(context->capability_ambient_set, true);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to apply ambient capabilities (before UID change)");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (before UID change): %m");
}
if (context->capabilities) {
@@ -2763,22 +3222,24 @@ static int exec_child(
}
}
+ }
+ if (needs_setuid) {
if (context->user) {
r = enforce_user(context, uid);
if (r < 0) {
*exit_status = EXIT_USER;
- (void) asprintf(error_message, "Failed to change UID to "UID_FMT, uid);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change UID to " UID_FMT ": %m", uid);
}
- if (context->capability_ambient_set != 0) {
+
+ if (!needs_ambient_hack &&
+ context->capability_ambient_set != 0) {
/* Fix the ambient capabilities after user change. */
r = capability_ambient_set_apply(context->capability_ambient_set, false);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
- *error_message = strdup("Failed to apply ambient capabilities (after UID change)");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply ambient capabilities (after UID change): %m");
}
/* If we were asked to change user and ambient capabilities
@@ -2791,56 +3252,54 @@ static int exec_child(
secure_bits |= 1<<SECURE_KEEP_CAPS;
}
}
+ }
+ if (needs_sandboxing) {
/* Apply the MAC contexts late, but before seccomp syscall filtering, as those should really be last to
* influence our own codepaths as little as possible. Moreover, applying MAC contexts usually requires
* syscalls that are subject to seccomp filtering, hence should probably be applied before the syscalls
* are restricted. */
-#ifdef HAVE_SELINUX
- if (mac_selinux_use()) {
+#if HAVE_SELINUX
+ if (use_selinux) {
char *exec_context = mac_selinux_context_net ?: context->selinux_context;
if (exec_context) {
r = setexeccon(exec_context);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
- (void) asprintf(error_message, "Failed to set SELinux context to %s", exec_context);
- return r;
+ return log_unit_error_errno(unit, r, "Failed to change SELinux context to %s: %m", exec_context);
}
}
}
#endif
- r = setup_smack(context, command);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- *error_message = strdup("Failed to set SMACK process label");
- return r;
+#if ENABLE_SMACK
+ if (use_smack) {
+ r = setup_smack(context, command);
+ if (r < 0) {
+ *exit_status = EXIT_SMACK_PROCESS_LABEL;
+ return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m");
+ }
}
+#endif
-#ifdef HAVE_APPARMOR
- if (context->apparmor_profile && mac_apparmor_use()) {
+#if HAVE_APPARMOR
+ if (use_apparmor && context->apparmor_profile) {
r = aa_change_onexec(context->apparmor_profile);
if (r < 0 && !context->apparmor_profile_ignore) {
*exit_status = EXIT_APPARMOR_PROFILE;
- (void) asprintf(error_message,
- "Failed to prepare AppArmor profile change to %s",
- context->apparmor_profile);
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to prepare AppArmor profile change to %s: %m", context->apparmor_profile);
}
}
#endif
- /* PR_GET_SECUREBITS is not privileged, while
- * PR_SET_SECUREBITS is. So to suppress
- * potential EPERMs we'll try not to call
- * PR_SET_SECUREBITS unless necessary. */
+ /* PR_GET_SECUREBITS is not privileged, while PR_SET_SECUREBITS is. So to suppress potential EPERMs
+ * we'll try not to call PR_SET_SECUREBITS unless necessary. */
if (prctl(PR_GET_SECUREBITS) != secure_bits)
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
- *error_message = strdup("Failed to set secure bits");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to set process secure bits: %m");
}
if (context->capabilities)
@@ -2852,83 +3311,91 @@ static int exec_child(
if (context_has_no_new_privileges(context))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
*exit_status = EXIT_NO_NEW_PRIVILEGES;
- *error_message = strdup("Failed to disable new privileges");
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to disable new privileges: %m");
}
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
r = apply_address_families(unit, context);
if (r < 0) {
*exit_status = EXIT_ADDRESS_FAMILIES;
- *error_message = strdup("Failed to restrict address families");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to restrict address families: %m");
}
r = apply_memory_deny_write_execute(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to disable writing to executable memory");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to disable writing to executable memory: %m");
}
r = apply_restrict_realtime(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply realtime restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m");
}
r = apply_restrict_namespaces(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply namespace restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply namespace restrictions: %m");
}
r = apply_protect_sysctl(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply sysctl restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply sysctl restrictions: %m");
}
r = apply_protect_kernel_modules(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply module loading restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply module loading restrictions: %m");
}
r = apply_private_devices(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to set up private devices");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to set up private devices: %m");
}
r = apply_syscall_archs(unit, context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply syscall architecture restrictions");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply syscall architecture restrictions: %m");
+ }
+
+ r = apply_lock_personality(unit, context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ return log_unit_error_errno(unit, r, "Failed to lock personalities: %m");
}
/* This really should remain the last step before the execve(), to make sure our own code is unaffected
* by the filter as little as possible. */
- r = apply_syscall_filter(unit, context);
+ r = apply_syscall_filter(unit, context, needs_ambient_hack);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply syscall filters");
- return r;
+ return log_unit_error_errno(unit, r, "Failed to apply system call filters: %m");
}
#endif
}
+ if (!strv_isempty(context->unset_environment)) {
+ char **ee = NULL;
+
+ ee = strv_env_delete(accum_env, 1, context->unset_environment);
+ if (!ee) {
+ *exit_status = EXIT_MEMORY;
+ return log_oom();
+ }
+
+ strv_free(accum_env);
+ accum_env = ee;
+ }
+
final_argv = replace_env_argv(argv, accum_env);
if (!final_argv) {
*exit_status = EXIT_MEMORY;
- *error_message = strdup("Failed to prepare process arguments");
- return -ENOMEM;
+ return log_oom();
}
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
@@ -2936,19 +3403,33 @@ static int exec_child(
line = exec_command_line(final_argv);
if (line) {
- log_open();
log_struct(LOG_DEBUG,
"EXECUTABLE=%s", command->path,
LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
NULL);
- log_close();
}
}
execve(command->path, final_argv, accum_env);
+
+ if (errno == ENOENT && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) {
+
+ log_struct_errno(LOG_INFO, errno,
+ "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Executable %s missing, skipping: %m",
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
+
+ return 0;
+ }
+
*exit_status = EXIT_EXEC;
- return -errno;
+ return log_unit_error_errno(unit, errno, "Failed to execute command: %m");
}
int exec_spawn(Unit *unit,
@@ -3014,14 +3495,15 @@ int exec_spawn(Unit *unit,
LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
"EXECUTABLE=%s", command->path,
LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
NULL);
+
pid = fork();
if (pid < 0)
return log_unit_error_errno(unit, errno, "Failed to fork: %m");
if (pid == 0) {
- int exit_status;
- _cleanup_free_ char *error_message = NULL;
+ int exit_status = EXIT_SUCCESS;
r = exec_child(unit,
command,
@@ -3037,35 +3519,18 @@ int exec_spawn(Unit *unit,
n_socket_fds,
files_env,
unit->manager->user_lookup_fds[1],
- &exit_status,
- &error_message);
+ &exit_status);
+
if (r < 0) {
- log_open();
- if (error_message)
- log_struct_errno(LOG_ERR, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "%s: %m",
- error_message),
- "EXECUTABLE=%s", command->path,
- NULL);
- else if (r == -ENOENT && command->ignore)
- log_struct_errno(LOG_INFO, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Skipped spawning %s: %m",
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
- else
- log_struct_errno(LOG_ERR, r,
- "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
+ log_struct_errno(LOG_ERR, r,
+ "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
+ LOG_UNIT_ID(unit),
+ LOG_UNIT_INVOCATION_ID(unit),
+ LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
+ exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
+ command->path),
+ "EXECUTABLE=%s", command->path,
+ NULL);
}
_exit(exit_status);
@@ -3088,6 +3553,8 @@ int exec_spawn(Unit *unit,
}
void exec_context_init(ExecContext *c) {
+ ExecDirectoryType i;
+
assert(c);
c->umask = 0022;
@@ -3098,19 +3565,22 @@ void exec_context_init(ExecContext *c) {
c->ignore_sigpipe = true;
c->timer_slack_nsec = NSEC_INFINITY;
c->personality = PERSONALITY_INVALID;
- c->runtime_directory_mode = 0755;
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
+ c->directories[i].mode = 0755;
c->capability_bounding_set = CAP_ALL;
c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
}
void exec_context_done(ExecContext *c) {
unsigned l;
+ ExecDirectoryType i;
assert(c);
c->environment = strv_free(c->environment);
c->environment_files = strv_free(c->environment_files);
c->pass_environment = strv_free(c->pass_environment);
+ c->unset_environment = strv_free(c->unset_environment);
for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
c->rlimit[l] = mfree(c->rlimit[l]);
@@ -3147,12 +3617,14 @@ void exec_context_done(ExecContext *c) {
c->utmp_id = mfree(c->utmp_id);
c->selinux_context = mfree(c->selinux_context);
c->apparmor_profile = mfree(c->apparmor_profile);
+ c->smack_process_label = mfree(c->smack_process_label);
c->syscall_filter = set_free(c->syscall_filter);
c->syscall_archs = set_free(c->syscall_archs);
c->address_families = set_free(c->address_families);
- c->runtime_directory = strv_free(c->runtime_directory);
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
+ c->directories[i].paths = strv_free(c->directories[i].paths);
}
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
@@ -3163,17 +3635,28 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_p
if (!runtime_prefix)
return 0;
- STRV_FOREACH(i, c->runtime_directory) {
+ STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths) {
_cleanup_free_ char *p;
p = strjoin(runtime_prefix, "/", *i);
if (!p)
return -ENOMEM;
- /* We execute this synchronously, since we need to be
- * sure this is gone when we start the service
+ /* We execute this synchronously, since we need to be sure this is gone when we start the service
* next. */
(void) rm_rf(p, REMOVE_ROOT);
+
+ /* Also destroy any matching subdirectory below /private/. This is done to support DynamicUser=1
+ * setups. Note that we don't conditionalize here on that though, as the namespace is same way, and it
+ * makes us a bit more robust towards changing unit settings. Or to say this differently: in the worst
+ * case this is a NOP. */
+
+ free(p);
+ p = strjoin(runtime_prefix, "/private/", *i);
+ if (!p)
+ return -ENOMEM;
+
+ (void) rm_rf(p, REMOVE_ROOT);
}
return 0;
@@ -3380,8 +3863,7 @@ static bool tty_may_match_dev_console(const char *tty) {
if (!tty)
return true;
- if (startswith(tty, "/dev/"))
- tty += 5;
+ tty = skip_dev_prefix(tty);
/* trivial identity? */
if (streq(tty, "console"))
@@ -3419,6 +3901,7 @@ static void strv_fprintf(FILE *f, char **l) {
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
char **e, **d;
unsigned i;
+ ExecDirectoryType dt;
int r;
assert(c);
@@ -3443,7 +3926,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sMountAPIVFS: %s\n"
"%sIgnoreSIGPIPE: %s\n"
"%sMemoryDenyWriteExecute: %s\n"
- "%sRestrictRealtime: %s\n",
+ "%sRestrictRealtime: %s\n"
+ "%sKeyringMode: %s\n",
prefix, c->umask,
prefix, c->working_directory ? c->working_directory : "/",
prefix, c->root_directory ? c->root_directory : "/",
@@ -3460,7 +3944,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->mount_apivfs),
prefix, yes_no(c->ignore_sigpipe),
prefix, yes_no(c->memory_deny_write_execute),
- prefix, yes_no(c->restrict_realtime));
+ prefix, yes_no(c->restrict_realtime),
+ prefix, exec_keyring_mode_to_string(c->keyring_mode));
if (c->root_image)
fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
@@ -3474,10 +3959,17 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
STRV_FOREACH(e, c->pass_environment)
fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
- fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+ STRV_FOREACH(e, c->unset_environment)
+ fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
- STRV_FOREACH(d, c->runtime_directory)
- fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+ fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
+
+ for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
+ fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
+
+ STRV_FOREACH(d, c->directories[dt].paths)
+ fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), *d);
+ }
if (c->nice_set)
fprintf(f,
@@ -3500,23 +3992,23 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
if (c->ioprio_set) {
_cleanup_free_ char *class_str = NULL;
- ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str);
- fprintf(f,
- "%sIOSchedulingClass: %s\n"
- "%sIOPriority: %i\n",
- prefix, strna(class_str),
- prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
+ r = ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str);
+ if (r >= 0)
+ fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
+
+ fprintf(f, "%sIOPriority: %lu\n", prefix, IOPRIO_PRIO_DATA(c->ioprio));
}
if (c->cpu_sched_set) {
_cleanup_free_ char *policy_str = NULL;
- sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
+ r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
+ if (r >= 0)
+ fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
+
fprintf(f,
- "%sCPUSchedulingPolicy: %s\n"
"%sCPUSchedulingPriority: %i\n"
"%sCPUSchedulingResetOnFork: %s\n",
- prefix, strna(policy_str),
prefix, c->cpu_sched_priority,
prefix, yes_no(c->cpu_sched_reset_on_fork));
}
@@ -3551,29 +4043,30 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->tty_vhangup),
prefix, yes_no(c->tty_vt_disallocate));
- if (c->std_output == EXEC_OUTPUT_SYSLOG ||
- c->std_output == EXEC_OUTPUT_KMSG ||
- c->std_output == EXEC_OUTPUT_JOURNAL ||
- c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
- c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
- c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_SYSLOG ||
- c->std_error == EXEC_OUTPUT_KMSG ||
- c->std_error == EXEC_OUTPUT_JOURNAL ||
- c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE) {
+ if (IN_SET(c->std_output,
+ EXEC_OUTPUT_SYSLOG,
+ EXEC_OUTPUT_KMSG,
+ EXEC_OUTPUT_JOURNAL,
+ EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
+ EXEC_OUTPUT_KMSG_AND_CONSOLE,
+ EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
+ IN_SET(c->std_error,
+ EXEC_OUTPUT_SYSLOG,
+ EXEC_OUTPUT_KMSG,
+ EXEC_OUTPUT_JOURNAL,
+ EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
+ EXEC_OUTPUT_KMSG_AND_CONSOLE,
+ EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
_cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
- log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
- log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
+ r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
+ if (r >= 0)
+ fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
- fprintf(f,
- "%sSyslogFacility: %s\n"
- "%sSyslogLevel: %s\n",
- prefix, strna(fac_str),
- prefix, strna(lvl_str));
+ r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
+ if (r >= 0)
+ fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
}
if (c->capabilities) {
@@ -3584,36 +4077,28 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sCapabilities: %s\n", prefix, t);
}
- if (c->secure_bits)
- fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
- prefix,
- (c->secure_bits & 1<<SECURE_KEEP_CAPS) ? " keep-caps" : "",
- (c->secure_bits & 1<<SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
- (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
- (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
- (c->secure_bits & 1<<SECURE_NOROOT) ? " noroot" : "",
- (c->secure_bits & 1<<SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
+ if (c->secure_bits) {
+ _cleanup_free_ char *str = NULL;
- if (c->capability_bounding_set != CAP_ALL) {
- unsigned long l;
- fprintf(f, "%sCapabilityBoundingSet:", prefix);
+ r = secure_bits_to_string_alloc(c->secure_bits, &str);
+ if (r >= 0)
+ fprintf(f, "%sSecure Bits: %s\n", prefix, str);
+ }
- for (l = 0; l <= cap_last_cap(); l++)
- if (c->capability_bounding_set & (UINT64_C(1) << l))
- fprintf(f, " %s", strna(capability_to_name(l)));
+ if (c->capability_bounding_set != CAP_ALL) {
+ _cleanup_free_ char *str = NULL;
- fputs("\n", f);
+ r = capability_set_to_string_alloc(c->capability_bounding_set, &str);
+ if (r >= 0)
+ fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
}
if (c->capability_ambient_set != 0) {
- unsigned long l;
- fprintf(f, "%sAmbientCapabilities:", prefix);
-
- for (l = 0; l <= cap_last_cap(); l++)
- if (c->capability_ambient_set & (UINT64_C(1) << l))
- fprintf(f, " %s", strna(capability_to_name(l)));
+ _cleanup_free_ char *str = NULL;
- fputs("\n", f);
+ r = capability_set_to_string_alloc(c->capability_ambient_set, &str);
+ if (r >= 0)
+ fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
}
if (c->user)
@@ -3623,7 +4108,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
- if (strv_length(c->supplementary_groups) > 0) {
+ if (!strv_isempty(c->supplementary_groups)) {
fprintf(f, "%sSupplementaryGroups:", prefix);
strv_fprintf(f, c->supplementary_groups);
fputs("\n", f);
@@ -3669,13 +4154,27 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sSELinuxContext: %s%s\n",
prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
+ if (c->apparmor_profile)
+ fprintf(f,
+ "%sAppArmorProfile: %s%s\n",
+ prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
+
+ if (c->smack_process_label)
+ fprintf(f,
+ "%sSmackProcessLabel: %s%s\n",
+ prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
+
if (c->personality != PERSONALITY_INVALID)
fprintf(f,
"%sPersonality: %s\n",
prefix, strna(personality_to_string(c->personality)));
+ fprintf(f,
+ "%sLockPersonality: %s\n",
+ prefix, yes_no(c->lock_personality));
+
if (c->syscall_filter) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
Iterator j;
void *id;
bool first = true;
@@ -3688,7 +4187,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
if (!c->syscall_whitelist)
fputc('~', f);
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
SET_FOREACH(id, c->syscall_filter, j) {
_cleanup_free_ char *name = NULL;
@@ -3706,7 +4205,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
}
if (c->syscall_archs) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
Iterator j;
void *id;
#endif
@@ -3715,7 +4214,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sSystemCallArchitectures:",
prefix);
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
SET_FOREACH(id, c->syscall_archs, j)
fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
#endif
@@ -4216,3 +4715,29 @@ static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
+
+static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
+ [EXEC_PRESERVE_NO] = "no",
+ [EXEC_PRESERVE_YES] = "yes",
+ [EXEC_PRESERVE_RESTART] = "restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
+
+static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
+ [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
+ [EXEC_DIRECTORY_STATE] = "StateDirectory",
+ [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
+ [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
+ [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
+
+static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
+ [EXEC_KEYRING_INHERIT] = "inherit",
+ [EXEC_KEYRING_PRIVATE] = "private",
+ [EXEC_KEYRING_SHARED] = "shared",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);
diff --git a/src/core/execute.h b/src/core/execute.h
index 2751b1dc11..fceed3fef8 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -72,6 +72,22 @@ typedef enum ExecOutput {
_EXEC_OUTPUT_INVALID = -1
} ExecOutput;
+typedef enum ExecPreserveMode {
+ EXEC_PRESERVE_NO,
+ EXEC_PRESERVE_YES,
+ EXEC_PRESERVE_RESTART,
+ _EXEC_PRESERVE_MODE_MAX,
+ _EXEC_PRESERVE_MODE_INVALID = -1
+} ExecPreserveMode;
+
+typedef enum ExecKeyringMode {
+ EXEC_KEYRING_INHERIT,
+ EXEC_KEYRING_PRIVATE,
+ EXEC_KEYRING_SHARED,
+ _EXEC_KEYRING_MODE_MAX,
+ _EXEC_KEYRING_MODE_INVALID = -1,
+} ExecKeyringMode;
+
struct ExecStatus {
dual_timestamp start_timestamp;
dual_timestamp exit_timestamp;
@@ -80,13 +96,19 @@ struct ExecStatus {
int status; /* as in sigingo_t::si_status */
};
+typedef enum ExecCommandFlags {
+ EXEC_COMMAND_IGNORE_FAILURE = 1,
+ EXEC_COMMAND_FULLY_PRIVILEGED = 2,
+ EXEC_COMMAND_NO_SETUID = 4,
+ EXEC_COMMAND_AMBIENT_MAGIC = 8,
+} ExecCommandFlags;
+
struct ExecCommand {
char *path;
char **argv;
ExecStatus exec_status;
+ ExecCommandFlags flags;
LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
- bool ignore:1;
- bool privileged:1;
};
struct ExecRuntime {
@@ -100,10 +122,26 @@ struct ExecRuntime {
int netns_storage_socket[2];
};
+typedef enum ExecDirectoryType {
+ EXEC_DIRECTORY_RUNTIME = 0,
+ EXEC_DIRECTORY_STATE,
+ EXEC_DIRECTORY_CACHE,
+ EXEC_DIRECTORY_LOGS,
+ EXEC_DIRECTORY_CONFIGURATION,
+ _EXEC_DIRECTORY_TYPE_MAX,
+ _EXEC_DIRECTORY_TYPE_INVALID = -1,
+} ExecDirectoryType;
+
+typedef struct ExecDirectory {
+ char **paths;
+ mode_t mode;
+} ExecDirectory;
+
struct ExecContext {
char **environment;
char **environment_files;
char **pass_environment;
+ char **unset_environment;
struct rlimit *rlimit[_RLIMIT_MAX];
char *working_directory, *root_directory, *root_image;
@@ -159,6 +197,8 @@ struct ExecContext {
bool smack_process_label_ignore;
char *smack_process_label;
+ ExecKeyringMode keyring_mode;
+
char **read_write_paths, **read_only_paths, **inaccessible_paths;
unsigned long mount_flags;
BindMount *bind_mounts;
@@ -200,6 +240,7 @@ struct ExecContext {
bool same_pgrp;
unsigned long personality;
+ bool lock_personality;
unsigned long restrict_namespaces; /* The CLONE_NEWxyz flags permitted to the unit's processes */
@@ -211,8 +252,8 @@ struct ExecContext {
Set *address_families;
bool address_families_whitelist:1;
- char **runtime_directory;
- mode_t runtime_directory_mode;
+ ExecPreserveMode runtime_directory_preserve_mode;
+ ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
bool memory_deny_write_execute;
bool restrict_realtime;
@@ -230,16 +271,20 @@ static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
}
typedef enum ExecFlags {
- EXEC_APPLY_PERMISSIONS = 1U << 0,
+ EXEC_APPLY_SANDBOXING = 1U << 0,
EXEC_APPLY_CHROOT = 1U << 1,
EXEC_APPLY_TTY_STDIN = 1U << 2,
EXEC_NEW_KEYRING = 1U << 3,
+ EXEC_PASS_LOG_UNIT = 1U << 4, /* Whether to pass the unit name to the service's journal stream connection */
+ EXEC_CHOWN_DIRECTORIES = 1U << 5, /* chown() the runtime/state/cache/log directories to the user we run as, under all conditions */
+ EXEC_NSS_BYPASS_BUS = 1U << 6, /* Set the SYSTEMD_NSS_BYPASS_BUS environment variable, to disable nss-systemd for dbus */
+ EXEC_CGROUP_DELEGATE = 1U << 7,
/* The following are not used by execute.c, but by consumers internally */
- EXEC_PASS_FDS = 1U << 4,
- EXEC_IS_CONTROL = 1U << 5,
- EXEC_SETENV_RESULT = 1U << 6,
- EXEC_SET_WATCHDOG = 1U << 7,
+ EXEC_PASS_FDS = 1U << 8,
+ EXEC_IS_CONTROL = 1U << 9,
+ EXEC_SETENV_RESULT = 1U << 10,
+ EXEC_SET_WATCHDOG = 1U << 11,
} ExecFlags;
struct ExecParameters {
@@ -254,11 +299,10 @@ struct ExecParameters {
ExecFlags flags;
bool selinux_context_net:1;
- bool cgroup_delegate:1;
CGroupMask cgroup_supported;
const char *cgroup_path;
- const char *runtime_prefix;
+ char **prefix;
const char *confirm_spawn;
@@ -332,3 +376,12 @@ ExecInput exec_input_from_string(const char *s) _pure_;
const char* exec_utmp_mode_to_string(ExecUtmpMode i) _const_;
ExecUtmpMode exec_utmp_mode_from_string(const char *s) _pure_;
+
+const char* exec_preserve_mode_to_string(ExecPreserveMode i) _const_;
+ExecPreserveMode exec_preserve_mode_from_string(const char *s) _pure_;
+
+const char* exec_keyring_mode_to_string(ExecKeyringMode i) _const_;
+ExecKeyringMode exec_keyring_mode_from_string(const char *s) _pure_;
+
+const char* exec_directory_type_to_string(ExecDirectoryType i) _const_;
+ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 7b5c98a57c..6c7b209977 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -33,7 +33,7 @@
#define IMA_POLICY_PATH "/etc/ima/ima-policy"
int ima_setup(void) {
-#ifdef HAVE_IMA
+#if ENABLE_IMA
_cleanup_fclose_ FILE *input = NULL;
_cleanup_close_ int imafd = -1;
unsigned lineno = 0;
@@ -93,6 +93,6 @@ int ima_setup(void) {
done:
log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH".");
-#endif /* HAVE_IMA */
+#endif /* ENABLE_IMA */
return 0;
}
diff --git a/src/core/ip-address-access.c b/src/core/ip-address-access.c
new file mode 100644
index 0000000000..cfb7d51c4f
--- /dev/null
+++ b/src/core/ip-address-access.c
@@ -0,0 +1,217 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 <stdio.h>
+#include <stdlib.h>
+
+#include "alloc-util.h"
+#include "bpf-firewall.h"
+#include "extract-word.h"
+#include "hostname-util.h"
+#include "ip-address-access.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+int config_parse_ip_address_access(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ IPAddressAccessItem **list = data;
+ const char *p;
+ int r;
+
+ assert(list);
+
+ if (isempty(rvalue)) {
+ *list = ip_address_access_free_all(*list);
+ return 0;
+ }
+
+ p = rvalue;
+
+ for (;;) {
+ _cleanup_free_ IPAddressAccessItem *a = NULL;
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ break;
+ }
+
+ a = new0(IPAddressAccessItem, 1);
+ if (!a)
+ return log_oom();
+
+ if (streq(word, "any")) {
+ /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
+
+ a->family = AF_INET;
+ LIST_APPEND(items, *list, a);
+
+ a = new0(IPAddressAccessItem, 1);
+ if (!a)
+ return log_oom();
+
+ a->family = AF_INET6;
+
+ } else if (is_localhost(word)) {
+ /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
+
+ a->family = AF_INET;
+ a->address.in.s_addr = htobe32(0x7f000000);
+ a->prefixlen = 8;
+ LIST_APPEND(items, *list, a);
+
+ a = new0(IPAddressAccessItem, 1);
+ if (!a)
+ return log_oom();
+
+ a->family = AF_INET6;
+ a->address.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+ a->prefixlen = 128;
+
+ } else if (streq(word, "link-local")) {
+
+ /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
+
+ a->family = AF_INET;
+ a->address.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
+ a->prefixlen = 16;
+ LIST_APPEND(items, *list, a);
+
+ a = new0(IPAddressAccessItem, 1);
+ if (!a)
+ return log_oom();
+
+ a->family = AF_INET6;
+ a->address.in6 = (struct in6_addr) {
+ .__in6_u.__u6_addr32[0] = htobe32(0xfe800000)
+ };
+ a->prefixlen = 64;
+
+ } else if (streq(word, "multicast")) {
+
+ /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
+
+ a->family = AF_INET;
+ a->address.in.s_addr = htobe32((UINT32_C(224) << 24));
+ a->prefixlen = 4;
+ LIST_APPEND(items, *list, a);
+
+ a = new0(IPAddressAccessItem, 1);
+ if (!a)
+ return log_oom();
+
+ a->family = AF_INET6;
+ a->address.in6 = (struct in6_addr) {
+ .__in6_u.__u6_addr32[0] = htobe32(0xff000000)
+ };
+ a->prefixlen = 8;
+
+ } else {
+ r = in_addr_prefix_from_string_auto(word, &a->family, &a->address, &a->prefixlen);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Address prefix is invalid, ignoring assignment: %s", word);
+ return 0;
+ }
+ }
+
+ LIST_APPEND(items, *list, a);
+ a = NULL;
+ }
+
+ *list = ip_address_access_reduce(*list);
+
+ if (*list) {
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0)
+ log_warning("File %s:%u configures an IP firewall (%s=%s), but the local system does not support BPF/cgroup based firewalling.\n"
+ "Proceeding WITHOUT firewalling in effect!", filename, line, lvalue, rvalue);
+ }
+
+ return 0;
+}
+
+IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first) {
+ IPAddressAccessItem *next, *p = first;
+
+ while (p) {
+ next = p->items_next;
+ free(p);
+
+ p = next;
+ }
+
+ return NULL;
+}
+
+IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first) {
+ IPAddressAccessItem *a, *b, *tmp;
+ int r;
+
+ /* Drops all entries from the list that are covered by another entry in full, thus removing all redundant
+ * entries. */
+
+ LIST_FOREACH_SAFE(items, a, tmp, first) {
+
+ /* Drop irrelevant bits */
+ (void) in_addr_mask(a->family, &a->address, a->prefixlen);
+
+ LIST_FOREACH(items, b, first) {
+
+ if (a == b)
+ continue;
+
+ if (a->family != b->family)
+ continue;
+
+ if (b->prefixlen > a->prefixlen)
+ continue;
+
+ r = in_addr_prefix_covers(b->family,
+ &b->address,
+ b->prefixlen,
+ &a->address);
+ if (r <= 0)
+ continue;
+
+ /* b covers a fully, then let's drop a */
+
+ LIST_REMOVE(items, first, a);
+ free(a);
+ }
+ }
+
+ return first;
+}
diff --git a/src/core/ip-address-access.h b/src/core/ip-address-access.h
new file mode 100644
index 0000000000..9aeab1f4f8
--- /dev/null
+++ b/src/core/ip-address-access.h
@@ -0,0 +1,38 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 "in-addr-util.h"
+#include "list.h"
+
+typedef struct IPAddressAccessItem IPAddressAccessItem;
+
+struct IPAddressAccessItem {
+ int family;
+ unsigned char prefixlen;
+ union in_addr_union address;
+ LIST_FIELDS(IPAddressAccessItem, items);
+};
+
+int config_parse_ip_address_access(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+
+IPAddressAccessItem* ip_address_access_free_all(IPAddressAccessItem *first);
+
+IPAddressAccessItem* ip_address_access_reduce(IPAddressAccessItem *first);
diff --git a/src/core/job.c b/src/core/job.c
index 8e2039d321..fb57f193fd 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -368,19 +368,13 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
switch (a) {
case JOB_START:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_STOP:
- return
- b == UNIT_INACTIVE ||
- b == UNIT_FAILED;
+ return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
case JOB_VERIFY_ACTIVE:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
+ return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
case JOB_RELOAD:
return
@@ -687,7 +681,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
/* Return generic strings */
if (t == JOB_START)
return generic_finished_start_job[result];
- else if (t == JOB_STOP || t == JOB_RESTART)
+ else if (IN_SET(t, JOB_STOP, JOB_RESTART))
return generic_finished_stop_job[result];
else if (t == JOB_RELOAD)
return generic_finished_reload_job[result];
@@ -806,21 +800,26 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
default:
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
NULL);
return;
}
log_struct(job_result_log_level[result],
LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
mid,
NULL);
}
static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
+ assert(u);
/* No message if the job did not actually do anything due to failed condition. */
if (t == JOB_START && result == JOB_DONE && !u->condition_result)
@@ -883,7 +882,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
goto finish;
}
- if (result == JOB_FAILED || result == JOB_INVALID)
+ if (IN_SET(result, JOB_FAILED, JOB_INVALID))
j->manager->n_failed_jobs++;
job_uninstall(j);
@@ -903,7 +902,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
* the unit itself. We don't treat JOB_CANCELED as failure in
* this context. And JOB_FAILURE is already handled by the
* unit itself. */
- if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
+ if (IN_SET(result, JOB_TIMEOUT, JOB_DEPENDENCY)) {
log_struct(LOG_NOTICE,
"JOB_TYPE=%s", job_type_to_string(t),
"JOB_RESULT=%s", job_result_to_string(result),
diff --git a/src/core/killall.c b/src/core/killall.c
index 3fe9fa2ed0..5e914e478d 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -174,8 +174,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
pid_t pid;
int r;
- if (d->d_type != DT_DIR &&
- d->d_type != DT_UNKNOWN)
+ if (!IN_SET(d->d_type, DT_DIR, DT_UNKNOWN))
continue;
if (parse_pid(d->d_name, &pid) < 0)
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 7d61a34cc6..8a9e8ff212 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -17,19 +17,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <ftw.h>
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
#include <libkmod.h>
#endif
+#include "alloc-util.h"
#include "bus-util.h"
#include "capability-util.h"
+#include "fileio.h"
#include "kmod-setup.h"
#include "macro.h"
+#include "string-util.h"
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
static void systemd_kmod_log(
void *data,
int priority,
@@ -43,10 +47,45 @@ static void systemd_kmod_log(
log_internalv(LOG_DEBUG, 0, file, line, fn, format, args);
REENABLE_WARNING;
}
+
+static int has_virtio_rng_nftw_cb(
+ const char *fpath,
+ const struct stat *sb,
+ int tflag,
+ struct FTW *ftwbuf) {
+
+ _cleanup_free_ char *alias = NULL;
+ int r;
+
+ if ((FTW_D == tflag) && (ftwbuf->level > 2))
+ return FTW_SKIP_SUBTREE;
+
+ if (FTW_F != tflag)
+ return FTW_CONTINUE;
+
+ if (!endswith(fpath, "/modalias"))
+ return FTW_CONTINUE;
+
+ r = read_one_line_file(fpath, &alias);
+ if (r < 0)
+ return FTW_SKIP_SIBLINGS;
+
+ if (startswith(alias, "pci:v00001AF4d00001005"))
+ return FTW_STOP;
+
+ if (startswith(alias, "pci:v00001AF4d00001044"))
+ return FTW_STOP;
+
+ return FTW_SKIP_SIBLINGS;
+}
+
+static bool has_virtio_rng(void) {
+ return (nftw("/sys/devices/pci0000:00", has_virtio_rng_nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL) == FTW_STOP);
+}
#endif
int kmod_setup(void) {
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
static const struct {
const char *module;
@@ -64,15 +103,17 @@ int kmod_setup(void) {
/* this should never be a module */
{ "unix", "/proc/net/unix", true, true, NULL },
-#ifdef ENABLE_KDBUS
+#if ENABLE_KDBUS
/* IPC is needed before we bring up any other services */
{ "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted },
#endif
-#ifdef HAVE_LIBIPTC
+#if HAVE_LIBIPTC
/* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
{ "ip_tables", "/proc/net/ip_tables_names", false, false, NULL },
#endif
+ /* virtio_rng would be loaded by udev later, but real entropy might be needed very early */
+ { "virtio_rng", NULL, false, false, has_virtio_rng },
};
struct kmod_ctx *ctx = NULL;
unsigned int i;
diff --git a/src/core/load-fragment-gperf-nulstr.awk b/src/core/load-fragment-gperf-nulstr.awk
index b52438abe3..44bc1fb698 100644
--- a/src/core/load-fragment-gperf-nulstr.awk
+++ b/src/core/load-fragment-gperf-nulstr.awk
@@ -4,7 +4,7 @@ BEGIN{
print "const char load_fragment_gperf_nulstr[] ="
}
keyword==1 {
- print "\"" $$1 "\\0\""
+ print "\"" $1 "\\0\""
}
/%%/ {
keyword=1
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 965c6e79ec..0e87e8d29e 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -35,6 +35,7 @@ $1.UMask, config_parse_mode, 0,
$1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment)
$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
$1.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment)
+$1.UnsetEnvironment, config_parse_unset_environ, 0, offsetof($1, exec_context.unset_environment)
$1.DynamicUser, config_parse_bool, true, offsetof($1, exec_context.dynamic_user)
$1.StandardInput, config_parse_exec_input, 0, offsetof($1, exec_context)
$1.StandardOutput, config_parse_exec_output, 0, offsetof($1, exec_context)
@@ -53,6 +54,7 @@ $1.CapabilityBoundingSet, config_parse_capability_set, 0,
$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
+$1.KeyringMode, config_parse_exec_keyring_mode, 0, offsetof($1, exec_context.keyring_mode)
m4_ifdef(`HAVE_SECCOMP',
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
@@ -60,14 +62,16 @@ $1.SystemCallErrorNumber, config_parse_syscall_errno, 0,
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
-$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
+$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)
+$1.LockPersonality, config_parse_bool, 0, offsetof($1, exec_context.lock_personality)',
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
+$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
@@ -104,8 +108,17 @@ $1.ProtectHome, config_parse_protect_home, 0,
$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
$1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs)
$1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality)
-$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode)
-$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
+$1.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode)
+$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode)
+$1.RuntimeDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].paths)
+$1.StateDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].mode)
+$1.StateDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_STATE].paths)
+$1.CacheDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].mode)
+$1.CacheDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CACHE].paths)
+$1.LogsDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].mode)
+$1.LogsDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths)
+$1.ConfigurationDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
+$1.ConfigurationDirectory, config_parse_exec_directories, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
m4_ifdef(`HAVE_PAM',
`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)',
`$1.PAMName, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
@@ -118,7 +131,7 @@ m4_ifdef(`HAVE_SELINUX',
m4_ifdef(`HAVE_APPARMOR',
`$1.AppArmorProfile, config_parse_exec_apparmor_profile, 0, offsetof($1, exec_context)',
`$1.AppArmorProfile, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-m4_ifdef(`HAVE_SMACK',
+m4_ifdef(`ENABLE_SMACK',
`$1.SmackProcessLabel, config_parse_exec_smack_process_label, 0, offsetof($1, exec_context)',
`$1.SmackProcessLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')'
)m4_dnl
@@ -161,6 +174,9 @@ $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0,
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
+$1.IPAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.ip_accounting)
+$1.IPAddressAllow, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_allow)
+$1.IPAddressDeny, config_parse_ip_address_access, 0, offsetof($1, cgroup_context.ip_address_deny)
$1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0'
)m4_dnl
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
@@ -193,8 +209,8 @@ Unit.OnFailureJobMode, config_parse_job_mode, 0,
Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode)
Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0
-Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
-Unit.JobRunningTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_running_timeout)
+Unit.JobTimeoutSec, config_parse_job_timeout_sec, 0, 0
+Unit.JobRunningTimeoutSec, config_parse_job_running_timeout_sec, 0, 0
Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, job_timeout_reboot_arg)
Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
@@ -340,7 +356,7 @@ Socket.FileDescriptorName, config_parse_fdname, 0,
Socket.Service, config_parse_socket_service, 0, 0
Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval)
Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst)
-m4_ifdef(`HAVE_SMACK',
+m4_ifdef(`ENABLE_SMACK',
`Socket.SmackLabel, config_parse_unit_string_printf, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_in)
Socket.SmackLabelIPOut, config_parse_unit_string_printf, 0, offsetof(Socket, smack_ip_out)',
@@ -354,15 +370,6 @@ EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
m4_dnl
-BusName.Name, config_parse_string, 0, offsetof(BusName, name)
-BusName.Activating, config_parse_bool, 0, offsetof(BusName, activating)
-BusName.Service, config_parse_busname_service, 0, 0
-BusName.AllowUser, config_parse_bus_policy, 0, 0
-BusName.AllowGroup, config_parse_bus_policy, 0, 0
-BusName.AllowWorld, config_parse_bus_policy_world, 0, offsetof(BusName, policy_world)
-BusName.SELinuxContext, config_parse_exec_selinux_context, 0, 0
-BusName.AcceptFileDescriptors, config_parse_bool, 0, offsetof(BusName, accept_fd)
-m4_dnl
Mount.What, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.what)
Mount.Where, config_parse_path, 0, offsetof(Mount, where)
Mount.Options, config_parse_unit_string_printf, 0, offsetof(Mount, parameters_fragment.options)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 58a76fc96b..61dd1d632b 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -22,7 +22,7 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/oom.h>
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include <seccomp.h>
#endif
#include <sched.h>
@@ -54,10 +54,11 @@
#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "securebits.h"
+#include "securebits-util.h"
#include "signal-util.h"
#include "stat-util.h"
#include "string-util.h"
@@ -282,6 +283,11 @@ int config_parse_unit_path_strv_printf(
assert(rvalue);
assert(u);
+ if (isempty(rvalue)) {
+ *x = strv_free(*x);
+ return 0;
+ }
+
for (p = rvalue;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
@@ -607,7 +613,8 @@ int config_parse_exec(
p = rvalue;
do {
_cleanup_free_ char *path = NULL, *firstword = NULL;
- bool separate_argv0 = false, ignore = false, privileged = false;
+ ExecCommandFlags flags = 0;
+ bool ignore = false, separate_argv0 = false;
_cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
@@ -621,18 +628,31 @@ int config_parse_exec(
f = firstword;
for (;;) {
- /* We accept an absolute path as first argument.
- * If it's prefixed with - and the path doesn't exist,
- * we ignore it instead of erroring out;
- * if it's prefixed with @, we allow overriding of argv[0];
- * and if it's prefixed with +, it will be run with full privileges */
- if (*f == '-' && !ignore)
+ /* We accept an absolute path as first argument. If it's prefixed with - and the path doesn't
+ * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
+ * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
+ * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
+ * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
+ * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
+ * other sandboxing, with some special exceptions for changing UID.
+ *
+ * The idea is that '!!' may be used to write services that can take benefit of systemd's
+ * UID/GID dropping if the kernel supports ambient creds, but provide an automatic fallback to
+ * privilege dropping within the daemon if the kernel does not offer that. */
+
+ if (*f == '-' && !(flags & EXEC_COMMAND_IGNORE_FAILURE)) {
+ flags |= EXEC_COMMAND_IGNORE_FAILURE;
ignore = true;
- else if (*f == '@' && !separate_argv0)
+ } else if (*f == '@' && !separate_argv0)
separate_argv0 = true;
- else if (*f == '+' && !privileged)
- privileged = true;
- else
+ else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
+ flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
+ else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
+ flags |= EXEC_COMMAND_NO_SETUID;
+ else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))) {
+ flags &= ~EXEC_COMMAND_NO_SETUID;
+ flags |= EXEC_COMMAND_AMBIENT_MAGIC;
+ } else
break;
f++;
}
@@ -751,8 +771,7 @@ int config_parse_exec(
nce->argv = n;
nce->path = path;
- nce->ignore = ignore;
- nce->privileged = privileged;
+ nce->flags = flags;
exec_command_append_list(e, nce);
@@ -1126,7 +1145,6 @@ int config_parse_exec_secure_bits(const char *unit,
void *userdata) {
ExecContext *c = data;
- const char *p;
int r;
assert(filename);
@@ -1140,38 +1158,18 @@ int config_parse_exec_secure_bits(const char *unit,
return 0;
}
- for (p = rvalue;;) {
- _cleanup_free_ char *word = NULL;
+ r = secure_bits_from_string(rvalue);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Invalid syntax, ignoring: %s", rvalue);
+ return 0;
+ }
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r == 0)
- return 0;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Invalid syntax, ignoring: %s", rvalue);
- return 0;
- }
+ c->secure_bits = r;
- if (streq(word, "keep-caps"))
- c->secure_bits |= 1<<SECURE_KEEP_CAPS;
- else if (streq(word, "keep-caps-locked"))
- c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
- else if (streq(word, "no-setuid-fixup"))
- c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
- else if (streq(word, "no-setuid-fixup-locked"))
- c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
- else if (streq(word, "noroot"))
- c->secure_bits |= 1<<SECURE_NOROOT;
- else if (streq(word, "noroot-locked"))
- c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
- else {
- log_syntax(unit, LOG_ERR, filename, line, 0,
- "Failed to parse secure bit \"%s\", ignoring.", word);
- return 0;
- }
- }
+ return 0;
}
int config_parse_capability_set(
@@ -1189,7 +1187,7 @@ int config_parse_capability_set(
uint64_t *capability_set = data;
uint64_t sum = 0, initial = 0;
bool invert = false;
- const char *p;
+ int r;
assert(filename);
assert(lvalue);
@@ -1201,32 +1199,16 @@ int config_parse_capability_set(
rvalue++;
}
- if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
+ if (streq(lvalue, "CapabilityBoundingSet"))
initial = CAP_ALL; /* initialized to all bits on */
/* else "AmbientCapabilities" initialized to all bits off */
- p = rvalue;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- int cap, r;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
- break;
- }
-
- cap = capability_from_name(word);
- if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
- continue;
- }
-
- sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
+ r = capability_set_from_string(rvalue, &sum);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word: %s", rvalue);
+ return 0;
}
if (sum == 0 || *capability_set == initial)
@@ -1284,7 +1266,7 @@ int config_parse_limit(
return 0;
}
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
unsigned line,
@@ -2006,15 +1988,7 @@ int config_parse_user_group_strv(
assert(u);
if (isempty(rvalue)) {
- char **empty;
-
- empty = new0(char*, 1);
- if (!empty)
- return log_oom();
-
- strv_free(*users);
- *users = empty;
-
+ *users = strv_free(*users);
return 0;
}
@@ -2053,115 +2027,6 @@ int config_parse_user_group_strv(
return 0;
}
-int config_parse_busname_service(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- BusName *n = data;
- int r;
- Unit *x;
- _cleanup_free_ char *p = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = unit_name_printf(UNIT(n), rvalue, &p);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
- return 0;
- }
-
- r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
- return 0;
- }
-
- unit_ref_set(&n->service, x);
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
-
-int config_parse_bus_policy(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ BusNamePolicy *p = NULL;
- _cleanup_free_ char *id_str = NULL;
- BusName *busname = data;
- char *access_str;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- p = new0(BusNamePolicy, 1);
- if (!p)
- return log_oom();
-
- if (streq(lvalue, "AllowUser"))
- p->type = BUSNAME_POLICY_TYPE_USER;
- else if (streq(lvalue, "AllowGroup"))
- p->type = BUSNAME_POLICY_TYPE_GROUP;
- else
- assert_not_reached("Unknown lvalue");
-
- id_str = strdup(rvalue);
- if (!id_str)
- return log_oom();
-
- access_str = strpbrk(id_str, WHITESPACE);
- if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
- return 0;
- }
-
- *access_str = '\0';
- access_str++;
- access_str += strspn(access_str, WHITESPACE);
-
- p->access = bus_policy_access_from_string(access_str);
- if (p->access < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
- return 0;
- }
-
- p->name = id_str;
- id_str = NULL;
-
- LIST_PREPEND(policy, busname->policy, p);
- p = NULL;
-
- return 0;
-}
-
int config_parse_working_directory(
const char *unit,
const char *filename,
@@ -2272,16 +2137,17 @@ int config_parse_unit_env_file(const char *unit,
return 0;
}
-int config_parse_environ(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_environ(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Unit *u = userdata;
char ***env = data;
@@ -2317,7 +2183,7 @@ int config_parse_environ(const char *unit,
r = unit_full_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to resolve specifiers, ignoring: %s", k);
+ "Failed to resolve specifiers, ignoring: %s", word);
continue;
}
} else {
@@ -2334,25 +2200,28 @@ int config_parse_environ(const char *unit,
r = strv_env_replace(env, k);
if (r < 0)
return log_oom();
+
k = NULL;
}
}
-int config_parse_pass_environ(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_pass_environ(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
const char *whole_rvalue = rvalue;
- char*** passenv = data;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
+ char*** passenv = data;
+ Unit *u = userdata;
int r;
assert(filename);
@@ -2367,7 +2236,7 @@ int config_parse_pass_environ(const char *unit,
}
for (;;) {
- _cleanup_free_ char *word = NULL;
+ _cleanup_free_ char *word = NULL, *k = NULL;
r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
if (r == 0)
@@ -2380,17 +2249,30 @@ int config_parse_pass_environ(const char *unit,
break;
}
- if (!env_name_is_valid(word)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid environment name for %s, ignoring: %s", lvalue, word);
+ if (u) {
+ r = unit_full_printf(u, word, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to resolve specifiers, ignoring: %s", word);
+ continue;
+ }
+ } else {
+ k = word;
+ word = NULL;
+ }
+
+ if (!env_name_is_valid(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Invalid environment name for %s, ignoring: %s", lvalue, k);
continue;
}
if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
return log_oom();
- n[nlen++] = word;
+
+ n[nlen++] = k;
n[nlen] = NULL;
- word = NULL;
+ k = NULL;
}
if (n) {
@@ -2402,6 +2284,85 @@ int config_parse_pass_environ(const char *unit,
return 0;
}
+int config_parse_unset_environ(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_strv_free_ char **n = NULL;
+ const char *whole_rvalue = rvalue;
+ size_t nlen = 0, nbufsize = 0;
+ char*** unsetenv = data;
+ Unit *u = userdata;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ *unsetenv = strv_free(*unsetenv);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
+
+ r = extract_first_word(&rvalue, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+ break;
+ }
+
+ if (u) {
+ r = unit_full_printf(u, word, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to resolve specifiers, ignoring: %s", word);
+ continue;
+ }
+ } else {
+ k = word;
+ word = NULL;
+ }
+
+ if (!env_assignment_is_valid(k) && !env_name_is_valid(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Invalid environment name or assignment %s, ignoring: %s", lvalue, k);
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
+ return log_oom();
+
+ n[nlen++] = k;
+ n[nlen] = NULL;
+ k = NULL;
+ }
+
+ if (n) {
+ r = strv_extend_strv(unsetenv, n, true);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
int config_parse_ip_tos(const char *unit,
const char *filename,
unsigned line,
@@ -2694,7 +2655,7 @@ int config_parse_documentation(const char *unit,
return r;
}
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
static int syscall_filter_parse_one(
const char *unit,
@@ -3735,7 +3696,9 @@ int config_parse_job_mode_isolate(
return 0;
}
-int config_parse_runtime_directory(
+DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode, ExecPreserveMode, "Failed to parse runtime directory preserve mode");
+
+int config_parse_exec_directories(
const char *unit,
const char *filename,
unsigned line,
@@ -3767,8 +3730,6 @@ int config_parse_runtime_directory(
_cleanup_free_ char *word = NULL, *k = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r == 0)
- return 0;
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
@@ -3776,6 +3737,8 @@ int config_parse_runtime_directory(
"Invalid syntax, ignoring: %s", rvalue);
return 0;
}
+ if (r == 0)
+ return 0;
r = unit_full_printf(u, word, &k);
if (r < 0) {
@@ -3784,9 +3747,9 @@ int config_parse_runtime_directory(
continue;
}
- if (!filename_is_valid(k)) {
+ if (!path_is_safe(k) || path_is_absolute(k)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
- "Runtime directory is not valid, ignoring assignment: %s", rvalue);
+ "%s= path is not valid, ignoring assignment: %s", lvalue, rvalue);
continue;
}
@@ -4212,6 +4175,80 @@ int config_parse_protect_system(
return 0;
}
+DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_keyring_mode, exec_keyring_mode, ExecKeyringMode, "Failed to parse keyring mode");
+
+int config_parse_job_timeout_sec(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Unit *u = data;
+ usec_t usec;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(u);
+
+ r = parse_sec_fix_0(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobTimeoutSec= parameter, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ /* If the user explicitly changed JobTimeoutSec= also change JobRunningTimeoutSec=, for compatibility with old
+ * versions. If JobRunningTimeoutSec= was explicitly set, avoid this however as whatever the user picked should
+ * count. */
+
+ if (!u->job_running_timeout_set)
+ u->job_running_timeout = usec;
+
+ u->job_timeout = usec;
+
+ return 0;
+}
+
+int config_parse_job_running_timeout_sec(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Unit *u = data;
+ usec_t usec;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(u);
+
+ r = parse_sec_fix_0(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse JobRunningTimeoutSec= parameter, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ u->job_running_timeout = usec;
+ u->job_running_timeout_set = true;
+
+ return 0;
+}
+
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
@@ -4551,7 +4588,7 @@ void unit_dump_config_items(FILE *f) {
const ConfigParserCallback callback;
const char *rvalue;
} table[] = {
-#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
+#if !HAVE_SYSV_COMPAT || !HAVE_SECCOMP || !HAVE_PAM || !HAVE_SELINUX || !ENABLE_SMACK || !HAVE_APPARMOR
{ config_parse_warn_compat, "NOTSUPPORTED" },
#endif
{ config_parse_int, "INTEGER" },
@@ -4585,7 +4622,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_exec, "PATH [ARGUMENT [...]]" },
{ config_parse_service_type, "SERVICETYPE" },
{ config_parse_service_restart, "SERVICERESTART" },
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
{ config_parse_sysv_priority, "SYSVPRIORITY" },
#endif
{ config_parse_kill_mode, "KILLMODE" },
@@ -4615,7 +4652,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_set_status, "STATUS" },
{ config_parse_service_sockets, "SOCKETS" },
{ config_parse_environ, "ENVIRON" },
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
{ config_parse_syscall_filter, "SYSCALLS" },
{ config_parse_syscall_archs, "ARCHS" },
{ config_parse_syscall_errno, "ERRNO" },
@@ -4635,7 +4672,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },
{ config_parse_long, "LONG" },
{ config_parse_socket_service, "SERVICE" },
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
{ config_parse_exec_selinux_context, "LABEL" },
#endif
{ config_parse_job_mode, "MODE" },
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 4e76a4e347..2473b6f005 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -66,9 +66,6 @@ int config_parse_trigger_unit(const char *unit, const char *filename, unsigned l
int config_parse_path_spec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_service(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_service_sockets(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_busname_service(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bus_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bus_policy_world(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_ip_tos(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_condition_path(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -83,6 +80,7 @@ int config_parse_syscall_archs(const char *unit, const char *filename, unsigned
int config_parse_syscall_errno(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_pass_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unset_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_cpu_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -103,7 +101,8 @@ int config_parse_exec_selinux_context(const char *unit, const char *filename, un
int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_smack_process_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_address_families(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_runtime_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_runtime_preserve_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_directories(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_set_status(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_namespace_path_strv(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_no_new_privileges(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -119,6 +118,9 @@ int config_parse_user_group(const char *unit, const char *filename, unsigned lin
int config_parse_user_group_strv(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_restrict_namespaces(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bind_paths(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_exec_keyring_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_job_timeout_sec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_job_running_timeout_sec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index 27f8843de6..dd25fc62be 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -23,6 +23,7 @@
%_userunitdir @userunitdir@
%_unitdir_user @userunitdir@
%_presetdir @systempresetdir@
+%_userpresetdir @userpresetdir@
%_udevhwdbdir @udevhwdbdir@
%_udevrulesdir @udevrulesdir@
%_journalcatalogdir @catalogdir@
diff --git a/src/core/main.c b/src/core/main.c
index e7a345e38b..8437fe0367 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -28,10 +28,10 @@
#include <sys/reboot.h>
#include <sys/stat.h>
#include <unistd.h>
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include <seccomp.h>
#endif
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
@@ -74,7 +74,7 @@
#include "process-util.h"
#include "raw-clone.h"
#include "rlimit-util.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "selinux-setup.h"
@@ -128,6 +128,7 @@ static Set* arg_syscall_archs = NULL;
static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
static bool arg_default_io_accounting = false;
+static bool arg_default_ip_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = true;
@@ -154,7 +155,7 @@ noreturn static void crash(int sig) {
struct sigaction sa;
pid_t pid;
- if (getpid() != 1)
+ if (getpid_cached() != 1)
/* Pass this on immediately, if this is not PID 1 */
(void) raise(sig);
else if (!arg_dump_core)
@@ -716,7 +717,7 @@ static int parse_config_file(void) {
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
{ "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
{ "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
#endif
{ "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec },
@@ -748,6 +749,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
+ { "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
@@ -792,6 +794,7 @@ static void manager_set_defaults(Manager *m) {
m->default_start_limit_burst = arg_default_start_limit_burst;
m->default_cpu_accounting = arg_default_cpu_accounting;
m->default_io_accounting = arg_default_io_accounting;
+ m->default_ip_accounting = arg_default_ip_accounting;
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
@@ -860,7 +863,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
- if (getpid() == 1)
+ if (getpid_cached() == 1)
opterr = 0;
while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0)
@@ -1066,7 +1069,7 @@ static int parse_argv(int argc, char *argv[]) {
* parse_proc_cmdline_word() or ignore. */
case '?':
- if (getpid() != 1)
+ if (getpid_cached() != 1)
return -EINVAL;
else
return 0;
@@ -1075,7 +1078,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option code.");
}
- if (optind < argc && getpid() != 1) {
+ if (optind < argc && getpid_cached() != 1) {
/* Hmm, when we aren't run as init system
* let's complain about excess arguments */
@@ -1091,6 +1094,7 @@ static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Starts up and maintains the system or user services.\n\n"
" -h --help Show this help\n"
+ " --version Show version\n"
" --test Determine startup sequence, dump it and exit\n"
" --no-pager Do not pipe output into a pager\n"
" --dump-configuration-items Dump understood unit configuration items\n"
@@ -1201,6 +1205,26 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
return 0;
}
+static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
+ int r;
+
+ assert(saved_rlimit);
+ assert(getuid() == 0);
+
+ /* BPF_MAP_TYPE_LPM_TRIE bpf maps are charged against RLIMIT_MEMLOCK, even though we have CAP_IPC_LOCK which
+ * should normally disable such checks. We need them to implement IPAccessAllow= and IPAccessDeny=, hence let's
+ * bump the value high enough for the root user. */
+
+ if (getrlimit(RLIMIT_MEMLOCK, saved_rlimit) < 0)
+ return log_warning_errno(errno, "Reading RLIMIT_MEMLOCK failed, ignoring: %m");
+
+ r = setrlimit_closest(RLIMIT_MEMLOCK, &RLIMIT_MAKE_CONST(1024ULL*1024ULL*16ULL));
+ if (r < 0)
+ return log_warning_errno(r, "Setting RLIMIT_MEMLOCK failed, ignoring: %m");
+
+ return 0;
+}
+
static void test_usr(void) {
/* Check that /usr is not a separate fs */
@@ -1240,7 +1264,7 @@ oom:
}
static int enforce_syscall_archs(Set *archs) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
int r;
if (!is_seccomp_available())
@@ -1384,11 +1408,11 @@ int main(int argc, char *argv[]) {
bool queue_default_job = false;
bool empty_etc = false;
char *switch_root_dir = NULL, *switch_root_init = NULL;
- struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0);
+ struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), saved_rlimit_memlock = RLIMIT_MAKE_CONST((rlim_t) -1);
const char *error_message = NULL;
-#ifdef HAVE_SYSV_COMPAT
- if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
+#if HAVE_SYSV_COMPAT
+ if (getpid_cached() != 1 && strstr(program_invocation_short_name, "init")) {
/* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
@@ -1424,7 +1448,7 @@ int main(int argc, char *argv[]) {
log_set_upgrade_syslog_to_journal(true);
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
/* Disable the umask logic */
umask(0);
@@ -1435,7 +1459,7 @@ int main(int argc, char *argv[]) {
log_set_always_reopen_console(true);
}
- if (getpid() == 1 && detect_container() <= 0) {
+ if (getpid_cached() == 1 && detect_container() <= 0) {
/* Running outside of a container as PID 1 */
arg_system = true;
@@ -1514,7 +1538,7 @@ int main(int argc, char *argv[]) {
* might redirect output elsewhere. */
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
- } else if (getpid() == 1) {
+ } else if (getpid_cached() == 1) {
/* Running inside a container, as PID 1 */
arg_system = true;
log_set_target(LOG_TARGET_CONSOLE);
@@ -1538,7 +1562,7 @@ int main(int argc, char *argv[]) {
kernel_timestamp = DUAL_TIMESTAMP_NULL;
}
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
/* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit)
* will process core dumps for system services by default. */
if (setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
@@ -1573,9 +1597,9 @@ int main(int argc, char *argv[]) {
/* Mount /proc, /sys and friends, so that /proc/cmdline and
* /proc/$PID/fd is available. */
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
- /* Load the kernel modules early, so that we kdbus.ko is loaded before kdbusfs shall be mounted */
+ /* Load the kernel modules early. */
if (!skip_setup)
kmod_setup();
@@ -1642,7 +1666,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_action == ACTION_TEST || arg_action == ACTION_HELP) {
+ if (IN_SET(arg_action, ACTION_TEST, ACTION_HELP)) {
pager_open(arg_no_pager, false);
skip_setup = true;
}
@@ -1666,26 +1690,28 @@ int main(int argc, char *argv[]) {
goto finish;
}
- assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST);
+ assert_se(IN_SET(arg_action, ACTION_RUN, ACTION_TEST));
/* Close logging fds, in order not to confuse fdset below */
log_close();
/* Remember open file descriptors for later deserialization */
- r = fdset_new_fill(&fds);
- if (r < 0) {
- log_emergency_errno(r, "Failed to allocate fd set: %m");
- error_message = "Failed to allocate fd set";
- goto finish;
- } else
- fdset_cloexec(fds, true);
+ if (arg_action == ACTION_RUN) {
+ r = fdset_new_fill(&fds);
+ if (r < 0) {
+ log_emergency_errno(r, "Failed to allocate fd set: %m");
+ error_message = "Failed to allocate fd set";
+ goto finish;
+ } else
+ fdset_cloexec(fds, true);
- if (arg_serialization)
- assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
+ if (arg_serialization)
+ assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
- if (arg_system)
- /* Become a session leader if we aren't one yet. */
- setsid();
+ if (arg_system)
+ /* Become a session leader if we aren't one yet. */
+ setsid();
+ }
/* Move out of the way, so that we won't block unmounts */
assert_se(chdir("/") == 0);
@@ -1699,7 +1725,7 @@ int main(int argc, char *argv[]) {
* tty. */
release_terminal();
- if (getpid() == 1 && !skip_setup)
+ if (getpid_cached() == 1 && !skip_setup)
console_setup();
}
@@ -1711,7 +1737,7 @@ int main(int argc, char *argv[]) {
/* Make sure we leave a core dump without panicing the
* kernel. */
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
install_crash_handler();
r = mount_cgroup_controllers(arg_join_controllers);
@@ -1755,66 +1781,64 @@ int main(int argc, char *argv[]) {
arg_action == ACTION_TEST ? " test" : "", getuid(), t);
}
- if (arg_system && !skip_setup) {
- if (arg_show_status > 0)
- status_welcome();
+ if (arg_action == ACTION_RUN) {
+ if (arg_system && !skip_setup) {
+ if (arg_show_status > 0)
+ status_welcome();
- hostname_setup();
- machine_id_setup(NULL, arg_machine_id, NULL);
- loopback_setup();
- bump_unix_max_dgram_qlen();
+ hostname_setup();
+ machine_id_setup(NULL, arg_machine_id, NULL);
+ loopback_setup();
+ bump_unix_max_dgram_qlen();
- test_usr();
- }
+ test_usr();
+ }
- if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
- watchdog_set_timeout(&arg_runtime_watchdog);
+ if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
+ watchdog_set_timeout(&arg_runtime_watchdog);
- if (arg_timer_slack_nsec != NSEC_INFINITY)
- if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
- log_error_errno(errno, "Failed to adjust timer slack: %m");
+ if (arg_timer_slack_nsec != NSEC_INFINITY)
+ if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
+ log_error_errno(errno, "Failed to adjust timer slack: %m");
- if (arg_system && !cap_test_all(arg_capability_bounding_set)) {
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
- if (r < 0) {
- log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
- error_message = "Failed to drop capability bounding set of usermode helpers";
- goto finish;
- }
- r = capability_bounding_set_drop(arg_capability_bounding_set, true);
- if (r < 0) {
- log_emergency_errno(r, "Failed to drop capability bounding set: %m");
- error_message = "Failed to drop capability bounding set";
- goto finish;
+ if (arg_system && !cap_test_all(arg_capability_bounding_set)) {
+ r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
+ if (r < 0) {
+ log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
+ error_message = "Failed to drop capability bounding set of usermode helpers";
+ goto finish;
+ }
+ r = capability_bounding_set_drop(arg_capability_bounding_set, true);
+ if (r < 0) {
+ log_emergency_errno(r, "Failed to drop capability bounding set: %m");
+ error_message = "Failed to drop capability bounding set";
+ goto finish;
+ }
}
- }
- if (arg_syscall_archs) {
- r = enforce_syscall_archs(arg_syscall_archs);
- if (r < 0) {
- error_message = "Failed to set syscall architectures";
- goto finish;
+ if (arg_syscall_archs) {
+ r = enforce_syscall_archs(arg_syscall_archs);
+ if (r < 0) {
+ error_message = "Failed to set syscall architectures";
+ goto finish;
+ }
}
- }
-
- if (!arg_system)
- /* Become reaper of our children */
- if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
- log_warning_errno(errno, "Failed to make us a subreaper: %m");
- if (arg_system) {
- (void) bump_rlimit_nofile(&saved_rlimit_nofile);
+ if (!arg_system)
+ /* Become reaper of our children */
+ if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
+ log_warning_errno(errno, "Failed to make us a subreaper: %m");
- if (empty_etc) {
- r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
- if (r < 0)
- log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m");
- else
- log_info("Populated /etc with preset unit settings.");
+ if (arg_system) {
+ /* Bump up RLIMIT_NOFILE for systemd itself */
+ (void) bump_rlimit_nofile(&saved_rlimit_nofile);
+ (void) bump_rlimit_memlock(&saved_rlimit_memlock);
}
}
- r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, arg_action == ACTION_TEST, &m);
+ r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ arg_action == ACTION_TEST ? MANAGER_TEST_FULL : 0,
+ &m);
if (r < 0) {
log_emergency_errno(r, "Failed to allocate manager object: %m");
error_message = "Failed to allocate manager object";
@@ -1862,7 +1886,7 @@ int main(int argc, char *argv[]) {
r = manager_load_unit(m, arg_default_unit, NULL, &error, &target);
if (r < 0)
log_error("Failed to load default target: %s", bus_error_message(&error, r));
- else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND)
+ else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND))
log_error_errno(target->load_error, "Failed to load default target: %m");
else if (target->load_state == UNIT_MASKED)
log_error("Default target masked.");
@@ -1875,7 +1899,7 @@ int main(int argc, char *argv[]) {
log_emergency("Failed to load rescue target: %s", bus_error_message(&error, r));
error_message = "Failed to load rescue target";
goto finish;
- } else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) {
+ } else if (IN_SET(target->load_state, UNIT_ERROR, UNIT_NOT_FOUND)) {
log_emergency_errno(target->load_error, "Failed to load rescue target: %m");
error_message = "Failed to load rescue target";
goto finish;
@@ -2043,6 +2067,8 @@ finish:
* its child processes */
if (saved_rlimit_nofile.rlim_cur > 0)
(void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
+ if (saved_rlimit_memlock.rlim_cur != (rlim_t) -1)
+ (void) setrlimit(RLIMIT_MEMLOCK, &saved_rlimit_memlock);
if (switch_root_dir) {
/* Kill all remaining processes from the
@@ -2140,12 +2166,12 @@ finish:
arg_serialization = safe_fclose(arg_serialization);
fds = fdset_free(fds);
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
/* If we are PID 1 and running under valgrind, then let's exit
* here explicitly. valgrind will only generate nice output on
* exit(), not on exec(), hence let's do the former not the
* latter here. */
- if (getpid() == 1 && RUNNING_ON_VALGRIND)
+ if (getpid_cached() == 1 && RUNNING_ON_VALGRIND)
return 0;
#endif
@@ -2221,10 +2247,10 @@ finish:
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",
- getpid() == 1 ? "freezing" : "quitting");
+ getpid_cached() == 1 ? "freezing" : "quitting");
}
- if (getpid() == 1) {
+ if (getpid_cached() == 1) {
if (error_message)
manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL,
diff --git a/src/core/manager.c b/src/core/manager.c
index b1de555334..7ae7a4ba5d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -30,12 +30,13 @@
#include <sys/wait.h>
#include <unistd.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#endif
#include "sd-daemon.h"
#include "sd-messages.h"
+#include "sd-path.h"
#include "alloc-util.h"
#include "audit-fd.h"
@@ -52,6 +53,7 @@
#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
+#include "execute.h"
#include "exec-util.h"
#include "exit-status.h"
#include "fd-util.h"
@@ -356,7 +358,7 @@ static int manager_setup_time_change(Manager *m) {
assert(m);
assert_cc(sizeof(time_t) == sizeof(TIME_T_MAX));
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
/* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
@@ -388,13 +390,13 @@ static int enable_special_signals(Manager *m) {
assert(m);
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
/* Enable that we get SIGINT on control-alt-del. In containers
* this will fail with EPERM (older) or EINVAL (newer), so
* ignore that. */
- if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
+ if (reboot(RB_DISABLE_CAD) < 0 && !IN_SET(errno, EPERM, EINVAL))
log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
@@ -556,7 +558,49 @@ static int manager_default_environment(Manager *m) {
return 0;
}
-int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
+static int manager_setup_prefix(Manager *m) {
+ struct table_entry {
+ uint64_t type;
+ const char *suffix;
+ };
+
+ static const struct table_entry paths_system[_EXEC_DIRECTORY_TYPE_MAX] = {
+ [EXEC_DIRECTORY_RUNTIME] = { SD_PATH_SYSTEM_RUNTIME, NULL },
+ [EXEC_DIRECTORY_STATE] = { SD_PATH_SYSTEM_STATE_PRIVATE, NULL },
+ [EXEC_DIRECTORY_CACHE] = { SD_PATH_SYSTEM_STATE_CACHE, NULL },
+ [EXEC_DIRECTORY_LOGS] = { SD_PATH_SYSTEM_STATE_LOGS, NULL },
+ [EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_SYSTEM_CONFIGURATION, NULL },
+ };
+
+ static const struct table_entry paths_user[_EXEC_DIRECTORY_TYPE_MAX] = {
+ [EXEC_DIRECTORY_RUNTIME] = { SD_PATH_USER_RUNTIME, NULL },
+ [EXEC_DIRECTORY_STATE] = { SD_PATH_USER_CONFIGURATION, NULL },
+ [EXEC_DIRECTORY_CACHE] = { SD_PATH_USER_STATE_CACHE, NULL },
+ [EXEC_DIRECTORY_LOGS] = { SD_PATH_USER_CONFIGURATION, "log" },
+ [EXEC_DIRECTORY_CONFIGURATION] = { SD_PATH_USER_CONFIGURATION, NULL },
+ };
+
+ const struct table_entry *p;
+ ExecDirectoryType i;
+ int r;
+
+ assert(m);
+
+ if (MANAGER_IS_SYSTEM(m))
+ p = paths_system;
+ else
+ p = paths_user;
+
+ for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
+ r = sd_path_home(p[i].type, p[i].suffix, &m->prefix[i]);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **_m) {
Manager *m;
int r;
@@ -572,8 +616,11 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
m->default_tasks_accounting = true;
m->default_tasks_max = UINT64_MAX;
+ m->default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
+ m->default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+ m->default_restart_usec = DEFAULT_RESTART_USEC;
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
#endif
@@ -584,13 +631,13 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->unit_log_format_string = "UNIT=%s";
m->invocation_log_field = "INVOCATION_ID=";
- m->invocation_log_format_string = "INVOCATION_ID=" SD_ID128_FORMAT_STR;
+ m->invocation_log_format_string = "INVOCATION_ID=%s";
} else {
m->unit_log_field = "USER_UNIT=";
m->unit_log_format_string = "USER_UNIT=%s";
m->invocation_log_field = "USER_INVOCATION_ID=";
- m->invocation_log_format_string = "USER_INVOCATION_ID=" SD_ID128_FORMAT_STR;
+ m->invocation_log_format_string = "USER_INVOCATION_ID=%s";
}
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
@@ -606,7 +653,7 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
- m->test_run = test_run;
+ m->test_run_flags = test_run_flags;
/* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
RATELIMIT_INIT(m->ctrl_alt_del_ratelimit, 2 * USEC_PER_SEC, 7);
@@ -673,6 +720,10 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
m->taint_usr = dir_is_empty("/usr") > 0;
+ r = manager_setup_prefix(m);
+ if (r < 0)
+ goto fail;
+
*_m = m;
return 0;
@@ -684,7 +735,7 @@ fail:
static int manager_setup_notify(Manager *m) {
int r;
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
if (m->notify_fd < 0) {
@@ -693,7 +744,6 @@ static int manager_setup_notify(Manager *m) {
.sa.sa_family = AF_UNIX,
};
static const int one = 1;
- const char *e;
/* First free all secondary fields */
m->notify_socket = mfree(m->notify_socket);
@@ -705,13 +755,7 @@ static int manager_setup_notify(Manager *m) {
fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
- e = manager_get_runtime_prefix(m);
- if (!e) {
- log_error("Failed to determine runtime prefix.");
- return -EINVAL;
- }
-
- m->notify_socket = strappend(e, "/systemd/notify");
+ m->notify_socket = strappend(m->prefix[EXEC_DIRECTORY_RUNTIME], "/systemd/notify");
if (!m->notify_socket)
return log_oom();
@@ -771,7 +815,7 @@ static int manager_setup_cgroups_agent(Manager *m) {
* to it. The system instance hence listens on this special socket, but the user instances listen on the system
* bus for these messages. */
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
if (!MANAGER_IS_SYSTEM(m))
@@ -816,7 +860,7 @@ static int manager_setup_cgroups_agent(Manager *m) {
* SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
* and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
* cgroup inotify for the unified cgroup stuff. */
- r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-4);
if (r < 0)
return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
@@ -831,7 +875,7 @@ static int manager_setup_kdbus(Manager *m) {
assert(m);
- if (m->test_run || m->kdbus_fd >= 0)
+ if (m->test_run_flags || m->kdbus_fd >= 0)
return 0;
if (!is_kdbus_available())
return -ESOCKTNOSUPPORT;
@@ -903,16 +947,20 @@ static int manager_setup_user_lookup_fd(Manager *m) {
static int manager_connect_bus(Manager *m, bool reexecuting) {
bool try_bus_connect;
+ Unit *u = NULL;
assert(m);
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
+ u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
+
try_bus_connect =
- m->kdbus_fd >= 0 ||
- reexecuting ||
- (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"));
+ (m->kdbus_fd >= 0) ||
+ ((u && UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) &&
+ (reexecuting ||
+ (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"))));
/* Try to connect to the buses, if possible. */
return bus_init(m, try_bus_connect);
@@ -961,10 +1009,8 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
assert(u);
- if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
- u->gc_marker == gc_marker + GC_OFFSET_BAD ||
- u->gc_marker == gc_marker + GC_OFFSET_UNSURE ||
- u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
+ if (IN_SET(u->gc_marker - gc_marker,
+ GC_OFFSET_GOOD, GC_OFFSET_BAD, GC_OFFSET_UNSURE, GC_OFFSET_IN_PATH))
return;
if (u->in_cleanup_queue)
@@ -1031,8 +1077,8 @@ static unsigned manager_dispatch_gc_unit_queue(Manager *m) {
n++;
- if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
- u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
+ if (IN_SET(u->gc_marker - gc_marker,
+ GC_OFFSET_BAD, GC_OFFSET_UNSURE)) {
if (u->id)
log_unit_debug(u, "Collecting.");
u->gc_marker = gc_marker + GC_OFFSET_BAD;
@@ -1095,6 +1141,7 @@ static void manager_clear_jobs_and_units(Manager *m) {
Manager* manager_free(Manager *m) {
UnitType c;
int i;
+ ExecDirectoryType dt;
if (!m)
return NULL;
@@ -1105,8 +1152,7 @@ Manager* manager_free(Manager *m) {
if (unit_vtable[c]->shutdown)
unit_vtable[c]->shutdown(m);
- /* If we reexecute ourselves, we keep the root cgroup
- * around */
+ /* If we reexecute ourselves, we keep the root cgroup around */
manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
lookup_paths_flush_generator(&m->lookup_paths);
@@ -1168,6 +1214,9 @@ Manager* manager_free(Manager *m) {
hashmap_free(m->uid_refs);
hashmap_free(m->gid_refs);
+ for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++)
+ m->prefix[dt] = mfree(m->prefix[dt]);
+
return mfree(m);
}
@@ -1287,7 +1336,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
assert(m);
- r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
+ /* If we are running in test mode, we still want to run the generators,
+ * but we should not touch the real generator directories. */
+ r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope,
+ m->test_run_flags ? LOOKUP_PATHS_TEMPORARY_GENERATED : 0,
+ NULL);
if (r < 0)
return r;
@@ -1295,12 +1348,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
- /* Make sure the transient directory always exists, so that it remains in the search path */
- if (!m->test_run) {
- r = mkdir_p_label(m->lookup_paths.transient, 0755);
- if (r < 0)
- return r;
- }
+ /* Make sure the transient directory always exists, so that it remains
+ * in the search path */
+ r = mkdir_p_label(m->lookup_paths.transient, 0755);
+ if (r < 0)
+ return r;
dual_timestamp_get(&m->generators_start_timestamp);
r = manager_run_generators(m);
@@ -1308,6 +1360,17 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (r < 0)
return r;
+ if (m->first_boot > 0 &&
+ m->unit_file_scope == UNIT_FILE_SYSTEM &&
+ !m->test_run_flags) {
+
+ q = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0);
+ if (q < 0)
+ log_full_errno(q == -EEXIST ? LOG_NOTICE : LOG_WARNING, q, "Failed to populate /etc with preset unit settings, ignoring: %m");
+ else
+ log_info("Populated /etc with preset unit settings.");
+ }
+
lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
@@ -1323,8 +1386,11 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
dual_timestamp_get(&m->units_load_finish_timestamp);
/* Second, deserialize if there is something to deserialize */
- if (serialization)
+ if (serialization) {
r = manager_deserialize(m, serialization, fds);
+ if (r < 0)
+ log_error_errno(r, "Deserialization failed: %m");
+ }
/* Any fds left? Find some unit which wants them. This is
* useful to allow container managers to pass some file
@@ -1405,7 +1471,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
return -ENOMEM;
r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
- mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
+ IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
mode == JOB_IGNORE_DEPENDENCIES, e);
if (r < 0)
goto tr_abort;
@@ -1469,6 +1535,40 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
return r;
}
+int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e) {
+ int r;
+ Transaction *tr;
+
+ assert(m);
+ assert(unit);
+ assert(mode < _JOB_MODE_MAX);
+ assert(mode != JOB_ISOLATE); /* Isolate is only valid for start */
+
+ tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
+ if (!tr)
+ return -ENOMEM;
+
+ /* We need an anchor job */
+ r = transaction_add_job_and_dependencies(tr, JOB_NOP, unit, NULL, false, false, true, true, e);
+ if (r < 0)
+ goto tr_abort;
+
+ /* Failure in adding individual dependencies is ignored, so this always succeeds. */
+ transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
+
+ r = transaction_activate(tr, m, mode, e);
+ if (r < 0)
+ goto tr_abort;
+
+ transaction_free(tr);
+ return 0;
+
+tr_abort:
+ transaction_abort(tr);
+ transaction_free(tr);
+ return r;
+}
+
Job *manager_get_job(Manager *m, uint32_t id) {
assert(m);
@@ -1721,7 +1821,7 @@ static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, ui
buf[n] = 0;
manager_notify_cgroup_empty(m, buf);
- bus_forward_agent_released(m, buf);
+ (void) bus_forward_agent_released(m, buf);
return 0;
}
@@ -1914,7 +2014,7 @@ static int manager_dispatch_sigchld(Manager *m) {
if (si.si_pid <= 0)
break;
- if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
+ if (IN_SET(si.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) {
_cleanup_free_ char *name = NULL;
Unit *u1, *u2, *u3;
@@ -1953,7 +2053,7 @@ static int manager_dispatch_sigchld(Manager *m) {
return 0;
}
-static int manager_start_target(Manager *m, const char *name, JobMode mode) {
+static void manager_start_target(Manager *m, const char *name, JobMode mode) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -1962,8 +2062,6 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
if (r < 0)
log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
-
- return r;
}
static void manager_handle_ctrl_alt_del(Manager *m) {
@@ -2033,17 +2131,11 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
/* Fall through */
case SIGINT:
- if (MANAGER_IS_SYSTEM(m)) {
+ if (MANAGER_IS_SYSTEM(m))
manager_handle_ctrl_alt_del(m);
- break;
- }
-
- /* Run the exit target if there is one, if not, just exit. */
- if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
- m->exit_code = MANAGER_EXIT;
- return 0;
- }
-
+ else
+ manager_start_target(m, SPECIAL_EXIT_TARGET,
+ JOB_REPLACE_IRREVERSIBLY);
break;
case SIGWINCH:
@@ -2111,14 +2203,17 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
default: {
/* Starting SIGRTMIN+0 */
- static const char * const target_table[] = {
- [0] = SPECIAL_DEFAULT_TARGET,
- [1] = SPECIAL_RESCUE_TARGET,
- [2] = SPECIAL_EMERGENCY_TARGET,
- [3] = SPECIAL_HALT_TARGET,
- [4] = SPECIAL_POWEROFF_TARGET,
- [5] = SPECIAL_REBOOT_TARGET,
- [6] = SPECIAL_KEXEC_TARGET
+ static const struct {
+ const char *target;
+ JobMode mode;
+ } target_table[] = {
+ [0] = { SPECIAL_DEFAULT_TARGET, JOB_ISOLATE },
+ [1] = { SPECIAL_RESCUE_TARGET, JOB_ISOLATE },
+ [2] = { SPECIAL_EMERGENCY_TARGET, JOB_ISOLATE },
+ [3] = { SPECIAL_HALT_TARGET, JOB_REPLACE_IRREVERSIBLY },
+ [4] = { SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY },
+ [5] = { SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY },
+ [6] = { SPECIAL_KEXEC_TARGET, JOB_REPLACE_IRREVERSIBLY }
};
/* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
@@ -2132,8 +2227,8 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
(int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
int idx = (int) sfsi.ssi_signo - SIGRTMIN;
- manager_start_target(m, target_table[idx],
- (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
+ manager_start_target(m, target_table[idx].target,
+ target_table[idx].mode);
break;
}
@@ -2301,7 +2396,7 @@ int manager_loop(Manager *m) {
if (manager_dispatch_cleanup_queue(m) > 0)
continue;
- if (manager_dispatch_cgroup_queue(m) > 0)
+ if (manager_dispatch_cgroup_realize_queue(m) > 0)
continue;
if (manager_dispatch_dbus_queue(m) > 0)
@@ -2391,7 +2486,7 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
_cleanup_free_ char *p = NULL;
const char *msg;
int audit_fd, r;
@@ -2447,9 +2542,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
if (detect_container() > 0)
return;
- if (u->type != UNIT_SERVICE &&
- u->type != UNIT_MOUNT &&
- u->type != UNIT_SWAP)
+ if (!IN_SET(u->type, UNIT_SERVICE, UNIT_MOUNT, UNIT_SWAP))
return;
/* We set SOCK_NONBLOCK here so that we rather drop the
@@ -2588,15 +2681,15 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
manager_serialize_uid_refs(m, f);
manager_serialize_gid_refs(m, f);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
HASHMAP_FOREACH_KEY(u, t, m->units, i) {
if (u->id != t)
continue;
/* Start marker */
- fputs(u->id, f);
- fputc('\n', f);
+ fputs_unlocked(u->id, f);
+ fputc_unlocked('\n', f);
r = unit_serialize(u, f, fds, !switching_root);
if (r < 0) {
@@ -2785,6 +2878,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
for (;;) {
Unit *u;
char name[UNIT_NAME_MAX+2];
+ const char* unit_name;
/* Start marker */
if (!fgets(name, sizeof(name), f)) {
@@ -2797,14 +2891,23 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
}
char_array_0(name);
+ unit_name = strstrip(name);
- r = manager_load_unit(m, strstrip(name), NULL, NULL, &u);
- if (r < 0)
- goto finish;
+ r = manager_load_unit(m, unit_name, NULL, NULL, &u);
+ if (r < 0) {
+ log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", unit_name);
+ if (r == -ENOMEM)
+ goto finish;
+ unit_deserialize_skip(f);
+ continue;
+ }
r = unit_deserialize(u, f, fds);
- if (r < 0)
- goto finish;
+ if (r < 0) {
+ log_notice_errno(r, "Failed to deserialize unit \"%s\": %m", unit_name);
+ if (r == -ENOMEM)
+ goto finish;
+ }
}
finish:
@@ -2877,8 +2980,12 @@ int manager_reload(Manager *m) {
/* Second, deserialize our stored data */
q = manager_deserialize(m, f, fds);
- if (q < 0 && r >= 0)
- r = q;
+ if (q < 0) {
+ log_error_errno(q, "Deserialization failed: %m");
+
+ if (r >= 0)
+ r = q;
+ }
fclose(f);
f = NULL;
@@ -2946,7 +3053,7 @@ static void manager_notify_finished(Manager *m) {
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
- if (m->test_run)
+ if (m->test_run_flags)
return;
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
@@ -3092,7 +3199,7 @@ static int manager_run_environment_generators(Manager *m) {
const char **paths;
void* args[] = {&tmp, &tmp, &m->environment};
- if (m->test_run)
+ if (m->test_run_flags && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS))
return 0;
paths = MANAGER_IS_SYSTEM(m) ? system_env_generator_binary_paths : user_env_generator_binary_paths;
@@ -3110,7 +3217,7 @@ static int manager_run_generators(Manager *m) {
assert(m);
- if (m->test_run)
+ if (m->test_run_flags && !(m->test_run_flags & MANAGER_TEST_RUN_GENERATORS))
return 0;
paths = generator_binary_paths(m->unit_file_scope);
@@ -3361,12 +3468,16 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
}
-const char *manager_get_runtime_prefix(Manager *m) {
+void manager_set_exec_params(Manager *m, ExecParameters *p) {
assert(m);
+ assert(p);
+
+ p->environment = m->environment;
+ p->confirm_spawn = manager_get_confirm_spawn(m);
+ p->cgroup_supported = m->cgroup_supported;
+ p->prefix = m->prefix;
- return MANAGER_IS_SYSTEM(m) ?
- "/run" :
- getenv("XDG_RUNTIME_DIR");
+ SET_FLAG(p->flags, EXEC_PASS_LOG_UNIT|EXEC_CHOWN_DIRECTORIES, MANAGER_IS_SYSTEM(m));
}
int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
@@ -3686,7 +3797,7 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
l = recv(fd, &buffer, sizeof(buffer), MSG_DONTWAIT);
if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
return 0;
return log_error_errno(errno, "Failed to read from user lookup fd: %m");
diff --git a/src/core/manager.h b/src/core/manager.h
index a4f8f766df..d5bb2dbb23 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -29,6 +29,7 @@
#include "cgroup-util.h"
#include "fdset.h"
#include "hashmap.h"
+#include "ip-address-access.h"
#include "list.h"
#include "ratelimit.h"
@@ -74,6 +75,15 @@ typedef enum StatusType {
#include "show-status.h"
#include "unit-name.h"
+enum {
+ /* 0 = run normally */
+ MANAGER_TEST_RUN_MINIMAL = 1, /* run test w/o generators */
+ MANAGER_TEST_RUN_ENV_GENERATORS = 2, /* also run env generators */
+ MANAGER_TEST_RUN_GENERATORS = 4, /* also run unit generators */
+ MANAGER_TEST_FULL = MANAGER_TEST_RUN_ENV_GENERATORS | MANAGER_TEST_RUN_GENERATORS,
+};
+assert_cc((MANAGER_TEST_FULL & UINT8_MAX) == MANAGER_TEST_FULL);
+
struct Manager {
/* Note that the set of units we know of is allowed to be
* inconsistent. However the subset of it that is loaded may
@@ -109,7 +119,10 @@ struct Manager {
LIST_HEAD(Job, gc_job_queue);
/* Units that should be realized */
- LIST_HEAD(Unit, cgroup_queue);
+ LIST_HEAD(Unit, cgroup_realize_queue);
+
+ /* Units whose cgroup ran empty */
+ LIST_HEAD(Unit, cgroup_empty_queue);
sd_event *event;
@@ -219,17 +232,19 @@ struct Manager {
CGroupMask cgroup_supported;
char *cgroup_root;
- /* Notifications from cgroups, when the unified hierarchy is
- * used is done via inotify. */
+ /* Notifications from cgroups, when the unified hierarchy is used is done via inotify. */
int cgroup_inotify_fd;
sd_event_source *cgroup_inotify_event_source;
Hashmap *cgroup_inotify_wd_unit;
+ /* A defer event for handling cgroup empty events and processing them after SIGCHLD in all cases. */
+ sd_event_source *cgroup_empty_event_source;
+
/* Make sure the user cannot accidentally unmount our cgroup
* file system */
int pin_cgroupfs_fd;
- int gc_marker;
+ unsigned gc_marker;
/* Flags */
ManagerExitCode exit_code:5;
@@ -238,7 +253,8 @@ struct Manager {
bool dispatching_dbus_queue:1;
bool taint_usr:1;
- bool test_run:1;
+
+ unsigned test_run_flags:8;
/* If non-zero, exit with the following value when the systemd
* process terminate. Useful for containers: systemd-nspawn could get
@@ -261,6 +277,7 @@ struct Manager {
bool default_io_accounting;
bool default_blockio_accounting;
bool default_tasks_accounting;
+ bool default_ip_accounting;
uint64_t default_tasks_max;
usec_t default_timer_accuracy_usec;
@@ -319,6 +336,9 @@ struct Manager {
const char *invocation_log_format_string;
int first_boot; /* tri-state */
+
+ /* prefixes of e.g. RuntimeDirectory= */
+ char *prefix[_EXEC_DIRECTORY_TYPE_MAX];
};
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
@@ -326,7 +346,7 @@ struct Manager {
#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
-int manager_new(UnitFileScope scope, bool test_run, Manager **m);
+int manager_new(UnitFileScope scope, unsigned test_run_flags, Manager **m);
Manager* manager_free(Manager *m);
void manager_enumerate(Manager *m);
@@ -344,6 +364,7 @@ int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e,
int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
+int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
@@ -383,7 +404,7 @@ void manager_flip_auto_status(Manager *m, bool enable);
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
-const char *manager_get_runtime_prefix(Manager *m);
+void manager_set_exec_params(Manager *m, ExecParameters *p);
ManagerState manager_state(Manager *m);
diff --git a/src/core/meson.build b/src/core/meson.build
index fb8f9dc36b..4355f9ca6d 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -1,120 +1,120 @@
libcore_la_sources = '''
- unit.c
- unit.h
- unit-printf.c
- unit-printf.h
- job.c
- job.h
- manager.c
- manager.h
- transaction.c
- transaction.h
- load-fragment.c
- load-fragment.h
- service.c
- service.h
- socket.c
- socket.h
- busname.c
- busname.h
- bus-policy.c
- bus-policy.h
- target.c
- target.h
- device.c
- device.h
- mount.c
- mount.h
+ audit-fd.c
+ audit-fd.h
automount.c
automount.h
- swap.c
- swap.h
- timer.c
- timer.h
- path.c
- path.h
- slice.c
- slice.h
- scope.c
- scope.h
- load-dropin.c
- load-dropin.h
- execute.c
- execute.h
- dynamic-user.c
- dynamic-user.h
- kill.c
- kill.h
- dbus.c
- dbus.h
- dbus-manager.c
- dbus-manager.h
- dbus-unit.c
- dbus-unit.h
+ bpf-firewall.c
+ bpf-firewall.h
+ cgroup.c
+ cgroup.h
+ chown-recursive.c
+ chown-recursive.h
+ dbus-automount.c
+ dbus-automount.h
+ dbus-cgroup.c
+ dbus-cgroup.h
+ dbus-device.c
+ dbus-device.h
+ dbus-execute.c
+ dbus-execute.h
dbus-job.c
dbus-job.h
+ dbus-kill.c
+ dbus-kill.h
+ dbus-manager.c
+ dbus-manager.h
+ dbus-mount.c
+ dbus-mount.h
+ dbus-path.c
+ dbus-path.h
+ dbus-scope.c
+ dbus-scope.h
dbus-service.c
dbus-service.h
+ dbus-slice.c
+ dbus-slice.h
dbus-socket.c
dbus-socket.h
- dbus-busname.c
- dbus-busname.h
- dbus-target.c
- dbus-target.h
- dbus-device.c
- dbus-device.h
- dbus-mount.c
- dbus-mount.h
- dbus-automount.c
- dbus-automount.h
dbus-swap.c
dbus-swap.h
+ dbus-target.c
+ dbus-target.h
dbus-timer.c
dbus-timer.h
- dbus-path.c
- dbus-path.h
- dbus-slice.c
- dbus-slice.h
- dbus-scope.c
- dbus-scope.h
- dbus-execute.c
- dbus-execute.h
- dbus-kill.c
- dbus-kill.h
- dbus-cgroup.c
- dbus-cgroup.h
- cgroup.c
- cgroup.h
- selinux-access.c
- selinux-access.h
- selinux-setup.c
- selinux-setup.h
- smack-setup.c
- smack-setup.h
+ dbus-unit.c
+ dbus-unit.h
+ dbus.c
+ dbus.h
+ device.c
+ device.h
+ dynamic-user.c
+ dynamic-user.h
+ emergency-action.c
+ emergency-action.h
+ execute.c
+ execute.h
+ hostname-setup.c
+ hostname-setup.h
ima-setup.c
ima-setup.h
- locale-setup.h
+ ip-address-access.c
+ ip-address-access.h
+ job.c
+ job.h
+ kill.c
+ kill.h
+ killall.c
+ killall.h
+ kmod-setup.c
+ kmod-setup.h
+ load-dropin.c
+ load-dropin.h
+ load-fragment.c
+ load-fragment.h
locale-setup.c
- hostname-setup.c
- hostname-setup.h
+ locale-setup.h
+ loopback-setup.c
+ loopback-setup.h
machine-id-setup.c
machine-id-setup.h
+ manager.c
+ manager.h
mount-setup.c
mount-setup.h
- kmod-setup.c
- kmod-setup.h
- loopback-setup.h
- loopback-setup.c
+ mount.c
+ mount.h
namespace.c
namespace.h
- killall.h
- killall.c
- audit-fd.c
- audit-fd.h
+ path.c
+ path.h
+ scope.c
+ scope.h
+ selinux-access.c
+ selinux-access.h
+ selinux-setup.c
+ selinux-setup.h
+ service.c
+ service.h
show-status.c
show-status.h
- emergency-action.c
- emergency-action.h
+ slice.c
+ slice.h
+ smack-setup.c
+ smack-setup.h
+ socket.c
+ socket.h
+ swap.c
+ swap.h
+ target.c
+ target.h
+ timer.c
+ timer.h
+ transaction.c
+ transaction.h
+ unit-printf.c
+ unit-printf.h
+ unit.c
+ unit.h
'''.split()
load_fragment_gperf_gperf = custom_target(
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 9214291899..9819082e8d 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -64,7 +64,7 @@ typedef struct MountPoint {
* fourth (securityfs) is needed by IMA to load a custom policy. The
* other ones we can delay until SELinux and IMA are loaded. When
* SMACK is enabled we need smackfs, too, so it's a fifth one. */
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
#define N_EARLY_MOUNT 5
#else
#define N_EARLY_MOUNT 4
@@ -79,7 +79,7 @@ static const MountPoint mount_table[] = {
NULL, MNT_FATAL|MNT_IN_CONTAINER },
{ "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
{ "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
mac_smack_use, MNT_FATAL },
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfstransmute=System::Run", MS_NOSUID|MS_NODEV|MS_STRICTATIME|MS_NOEXEC,
@@ -90,7 +90,7 @@ static const MountPoint mount_table[] = {
#endif
{ "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
NULL, MNT_IN_CONTAINER },
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
{ "tmpfs", "/run", "tmpfs", "mode=755,smackfstransmute=System::Run", MS_NOSUID|MS_NODEV|MS_STRICTATIME|MS_NOEXEC,
mac_smack_use, MNT_FATAL },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
@@ -98,11 +98,15 @@ static const MountPoint mount_table[] = {
#else
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME|MS_NOEXEC,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_unified_wanted, MNT_IN_CONTAINER },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
#endif
+ { "cgroup", "/sys/fs/cgroup", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_unified_wanted, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_unified_wanted, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_hybrid_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_hybrid_wanted, MNT_IN_CONTAINER },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
@@ -111,12 +115,12 @@ static const MountPoint mount_table[] = {
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
{ "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
is_efi_boot, MNT_NONE },
#endif
-#ifdef ENABLE_KDBUS
-#ifdef HAVE_SMACK
+#if ENABLE_KDBUS
+#if ENABLE_SMACK
{ "kdbusfs", "/sys/fs/kdbus", "kdbusfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
is_kdbus_wanted, MNT_IN_CONTAINER },
#else
@@ -350,7 +354,7 @@ int mount_cgroup_controllers(char ***join_controllers) {
return 0;
}
-#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+#if HAVE_SELINUX || ENABLE_SMACK
static int nftw_cb(
const char *fpath,
const struct stat *sb,
@@ -381,7 +385,7 @@ int mount_setup(bool loaded_policy) {
if (r < 0)
return r;
-#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+#if HAVE_SELINUX || ENABLE_SMACK
/* Nodes in devtmpfs and /run need to be manually updated for
* the appropriate labels, after mounting. The other virtual
* API file systems like /sys and /proc do not need that, they
diff --git a/src/core/mount.c b/src/core/mount.c
index 214364d87d..903b3a9c1b 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -58,8 +58,6 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
[MOUNT_MOUNTED] = UNIT_ACTIVE,
[MOUNT_REMOUNTING] = UNIT_RELOADING,
[MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
[MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
[MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
[MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
@@ -70,6 +68,18 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
+ return IN_SET(state,
+ MOUNT_MOUNTING,
+ MOUNT_MOUNTING_DONE,
+ MOUNT_REMOUNTING,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL);
+}
+
static bool mount_needs_network(const char *options, const char *fstype) {
if (fstab_test_option(options, "_netdev\0"))
return true;
@@ -121,20 +131,6 @@ static bool mount_is_automount(const MountParameters *p) {
"x-systemd.automount\0");
}
-static bool mount_state_active(MountState state) {
- return IN_SET(state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL);
-}
-
static bool mount_is_bound_to_device(const Mount *m) {
const MountParameters *p;
@@ -503,7 +499,7 @@ static int mount_verify(Mount *m) {
if (UNIT(m)->load_state != UNIT_LOADED)
return 0;
- if (!m->from_fragment && !m->from_proc_self_mountinfo)
+ if (!m->from_fragment && !m->from_proc_self_mountinfo && !UNIT(m)->perpetual)
return -ENOENT;
r = unit_name_from_path(m->where, ".mount", &e);
@@ -642,7 +638,7 @@ static void mount_set_state(Mount *m, MountState state) {
old_state = m->state;
m->state = state;
- if (!mount_state_active(state)) {
+ if (!MOUNT_STATE_WITH_PROCESS(state)) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
mount_unwatch_control_pid(m);
m->control_command = NULL;
@@ -653,7 +649,6 @@ static void mount_set_state(Mount *m, MountState state) {
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
- m->reload_result = MOUNT_SUCCESS;
}
static int mount_coldplug(Unit *u) {
@@ -674,7 +669,7 @@ static int mount_coldplug(Unit *u) {
if (m->control_pid > 0 &&
pid_is_unwaited(m->control_pid) &&
- mount_state_active(new_state)) {
+ MOUNT_STATE_WITH_PROCESS(new_state)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
@@ -736,13 +731,14 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
exec_context_dump(&m->exec_context, f, prefix);
kill_context_dump(&m->kill_context, f, prefix);
+ cgroup_context_dump(&m->cgroup_context, f, prefix);
}
static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -753,9 +749,10 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
assert(_pid);
(void) unit_realize_cgroup(UNIT(m));
- if (m->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(m));
- m->reset_cpu_usage = false;
+ if (m->reset_accounting) {
+ (void) unit_reset_cpu_accounting(UNIT(m));
+ (void) unit_reset_ip_accounting(UNIT(m));
+ m->reset_accounting = false;
}
r = unit_setup_exec_runtime(UNIT(m));
@@ -770,12 +767,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
if (r < 0)
return r;
- exec_params.environment = UNIT(m)->manager->environment;
- exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(m)->manager);
- exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(m)->cgroup_path;
- exec_params.cgroup_delegate = m->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
+ manager_set_exec_params(UNIT(m)->manager, &exec_params);
+ unit_set_exec_params(UNIT(m), &exec_params);
r = exec_spawn(UNIT(m),
c,
@@ -803,12 +796,15 @@ static void mount_enter_dead(Mount *m, MountResult f) {
if (m->result == MOUNT_SUCCESS)
m->result = f;
+ if (m->result != MOUNT_SUCCESS)
+ log_unit_warning(UNIT(m), "Failed with result '%s'.", mount_result_to_string(m->result));
+
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
exec_runtime_destroy(m->exec_runtime);
m->exec_runtime = exec_runtime_unref(m->exec_runtime);
- exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
+ exec_context_destroy_runtime_directory(&m->exec_context, UNIT(m)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
unit_unref_uid_gid(UNIT(m), true);
@@ -824,6 +820,35 @@ static void mount_enter_mounted(Mount *m, MountResult f) {
mount_set_state(m, MOUNT_MOUNTED);
}
+static void mount_enter_dead_or_mounted(Mount *m, MountResult f) {
+ assert(m);
+
+ /* Enter DEAD or MOUNTED state, depending on what the kernel currently says about the mount point. We use this
+ * whenever we executed an operation, so that our internal state reflects what the kernel says again, after all
+ * ultimately we just mirror the kernel's internal state on this. */
+
+ if (m->from_proc_self_mountinfo)
+ mount_enter_mounted(m, f);
+ else
+ mount_enter_dead(m, f);
+}
+
+static int state_to_kill_operation(MountState state) {
+ switch (state) {
+
+ case MOUNT_REMOUNTING_SIGTERM:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ return KILL_TERMINATE;
+
+ case MOUNT_REMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ return KILL_KILL;
+
+ default:
+ return _KILL_OPERATION_INVALID;
+ }
+}
+
static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
int r;
@@ -835,8 +860,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
r = unit_kill_context(
UNIT(m),
&m->kill_context,
- (state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM) ?
- KILL_KILL : KILL_TERMINATE,
+ state_to_kill_operation(state),
-1,
m->control_pid,
false);
@@ -849,26 +873,20 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
goto fail;
mount_set_state(m, state);
- } else if (state == MOUNT_REMOUNTING_SIGTERM)
+ } else if (state == MOUNT_REMOUNTING_SIGTERM && m->kill_context.send_sigkill)
mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_REMOUNTING_SIGKILL)
+ else if (IN_SET(state, MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL))
mount_enter_mounted(m, MOUNT_SUCCESS);
- else if (state == MOUNT_MOUNTING_SIGTERM)
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_UNMOUNTING_SIGTERM)
+ else if (state == MOUNT_UNMOUNTING_SIGTERM && m->kill_context.send_sigkill)
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS);
else
- mount_enter_dead(m, MOUNT_SUCCESS);
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
return;
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to kill processes: %m");
-
- if (IN_SET(state, MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL))
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
- else
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
}
static void mount_enter_unmounting(Mount *m) {
@@ -906,7 +924,7 @@ static void mount_enter_unmounting(Mount *m) {
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'umount' task: %m");
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
}
static void mount_enter_mounting(Mount *m) {
@@ -947,7 +965,6 @@ static void mount_enter_mounting(Mount *m) {
r = exec_command_append(m->control_command, "-o", opts, NULL);
} else
r = -ENOENT;
-
if (r < 0)
goto fail;
@@ -963,7 +980,17 @@ static void mount_enter_mounting(Mount *m) {
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'mount' task: %m");
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_RESOURCES);
+}
+
+static void mount_set_reload_result(Mount *m, MountResult result) {
+ assert(m);
+
+ /* Only store the first error we encounter */
+ if (m->reload_result != MOUNT_SUCCESS)
+ return;
+
+ m->reload_result = result;
}
static void mount_enter_remounting(Mount *m) {
@@ -972,6 +999,9 @@ static void mount_enter_remounting(Mount *m) {
assert(m);
+ /* Reset reload result when we are about to start a new remount operation */
+ m->reload_result = MOUNT_SUCCESS;
+
m->control_command_id = MOUNT_EXEC_REMOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
@@ -993,7 +1023,6 @@ static void mount_enter_remounting(Mount *m) {
r = exec_command_append(m->control_command, "-t", p->fstype, NULL);
} else
r = -ENOENT;
-
if (r < 0)
goto fail;
@@ -1009,8 +1038,8 @@ static void mount_enter_remounting(Mount *m) {
fail:
log_unit_warning_errno(UNIT(m), r, "Failed to run 'remount' task: %m");
- m->reload_result = MOUNT_FAILURE_RESOURCES;
- mount_enter_mounted(m, MOUNT_SUCCESS);
+ mount_set_reload_result(m, MOUNT_FAILURE_RESOURCES);
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
}
static int mount_start(Unit *u) {
@@ -1024,9 +1053,7 @@ static int mount_start(Unit *u) {
if (IN_SET(m->state,
MOUNT_UNMOUNTING,
MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL))
+ MOUNT_UNMOUNTING_SIGKILL))
return -EAGAIN;
/* Already on it! */
@@ -1047,7 +1074,7 @@ static int mount_start(Unit *u) {
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
- m->reset_cpu_usage = true;
+ m->reset_accounting = true;
mount_enter_mounting(m);
return 1;
@@ -1058,25 +1085,38 @@ static int mount_stop(Unit *u) {
assert(m);
- /* Already on it */
- if (IN_SET(m->state,
- MOUNT_UNMOUNTING,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL))
+ switch (m->state) {
+
+ case MOUNT_UNMOUNTING:
+ case MOUNT_UNMOUNTING_SIGKILL:
+ case MOUNT_UNMOUNTING_SIGTERM:
+ /* Already on it */
return 0;
- assert(IN_SET(m->state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL));
+ case MOUNT_MOUNTING:
+ case MOUNT_MOUNTING_DONE:
+ case MOUNT_REMOUNTING:
+ /* If we are still waiting for /bin/mount, we go directly into kill mode. */
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_SUCCESS);
+ return 0;
- mount_enter_unmounting(m);
- return 1;
+ case MOUNT_REMOUNTING_SIGTERM:
+ /* If we are already waiting for a hung remount, convert this to the matching unmounting state */
+ mount_set_state(m, MOUNT_UNMOUNTING_SIGTERM);
+ return 0;
+
+ case MOUNT_REMOUNTING_SIGKILL:
+ /* as above */
+ mount_set_state(m, MOUNT_UNMOUNTING_SIGKILL);
+ return 0;
+
+ case MOUNT_MOUNTED:
+ mount_enter_unmounting(m);
+ return 1;
+
+ default:
+ assert_not_reached("Unexpected state.");
+ }
}
static int mount_reload(Unit *u) {
@@ -1084,12 +1124,13 @@ static int mount_reload(Unit *u) {
assert(m);
- if (m->state == MOUNT_MOUNTING_DONE)
+ if (m->state == MOUNT_MOUNTING_DONE) /* not yet ready to reload, try again */
return -EAGAIN;
assert(m->state == MOUNT_MOUNTED);
mount_enter_remounting(m);
+
return 1;
}
@@ -1212,7 +1253,9 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown code");
- if (m->result == MOUNT_SUCCESS)
+ if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM))
+ mount_set_reload_result(m, f);
+ else if (m->result == MOUNT_SUCCESS)
m->result = f;
if (m->control_command) {
@@ -1225,19 +1268,15 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
log_unit_full(u, f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
"Mount process exited, code=%s status=%i", sigchld_code_to_string(code), status);
- /* Note that mount(8) returning and the kernel sending us a
- * mount table change event might happen out-of-order. If an
- * operation succeed we assume the kernel will follow soon too
- * and already change into the resulting state. If it fails
- * we check if the kernel still knows about the mount. and
- * change state accordingly. */
+ /* Note that mount(8) returning and the kernel sending us a mount table change event might happen
+ * out-of-order. If an operation succeed we assume the kernel will follow soon too and already change into the
+ * resulting state. If it fails we check if the kernel still knows about the mount. and change state
+ * accordingly. */
switch (m->state) {
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_MOUNTING_SIGTERM:
if (f == MOUNT_SUCCESS || m->from_proc_self_mountinfo)
/* If /bin/mount returned success, or if we see the mount point in /proc/self/mountinfo we are
@@ -1249,49 +1288,32 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case MOUNT_REMOUNTING:
- case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGTERM:
-
- m->reload_result = f;
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
+ case MOUNT_REMOUNTING_SIGKILL:
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
break;
case MOUNT_UNMOUNTING:
case MOUNT_UNMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGTERM:
- if (f == MOUNT_SUCCESS) {
-
- if (m->from_proc_self_mountinfo) {
-
- /* Still a mount point? If so, let's
- * try again. Most likely there were
- * multiple mount points stacked on
- * top of each other. Note that due to
- * the io event priority logic we can
- * be sure the new mountinfo is loaded
- * before we process the SIGCHLD for
- * the mount command. */
-
- if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
- log_unit_debug(u, "Mount still present, trying again.");
- m->n_retry_umount++;
- mount_enter_unmounting(m);
- } else {
- log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
- mount_enter_mounted(m, f);
- }
- } else
- mount_enter_dead(m, f);
-
- } else if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, f);
- else
+ if (m->from_proc_self_mountinfo) {
+
+ /* Still a mount point? If so, let's try again. Most likely there were multiple mount points
+ * stacked on top of each other. Note that due to the io event priority logic we can be sure
+ * the new mountinfo is loaded before we process the SIGCHLD for the mount command. */
+
+ if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
+ log_unit_debug(u, "Mount still present, trying again.");
+ m->n_retry_umount++;
+ mount_enter_unmounting(m);
+ } else {
+ log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount);
+ mount_enter_mounted(m, f);
+ }
+ } else
mount_enter_dead(m, f);
+
break;
default:
@@ -1312,72 +1334,53 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- log_unit_warning(UNIT(m), "Mounting timed out. Stopping.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mounting timed out. Terminating.");
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_REMOUNTING:
- log_unit_warning(UNIT(m), "Remounting timed out. Stopping.");
- m->reload_result = MOUNT_FAILURE_TIMEOUT;
- mount_enter_mounted(m, MOUNT_SUCCESS);
+ log_unit_warning(UNIT(m), "Remounting timed out. Killing remount process.");
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
+ mount_enter_signal(m, MOUNT_REMOUNTING_SIGTERM, MOUNT_SUCCESS);
break;
- case MOUNT_UNMOUNTING:
- log_unit_warning(UNIT(m), "Unmounting timed out. Stopping.");
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
+ case MOUNT_REMOUNTING_SIGTERM:
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
- case MOUNT_MOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Mounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Remounting timed out. Killing.");
+ mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS);
} else {
- log_unit_warning(UNIT(m), "Mounting timed out. Skipping SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
}
break;
- case MOUNT_REMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Remounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
+ case MOUNT_REMOUNTING_SIGKILL:
+ mount_set_reload_result(m, MOUNT_FAILURE_TIMEOUT);
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
+ log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_SUCCESS);
+ break;
+
+ case MOUNT_UNMOUNTING:
+ log_unit_warning(UNIT(m), "Unmounting timed out. Stopping.");
+ mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_UNMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m), "Unmounting timed out. Killing.");
+ log_unit_warning(UNIT(m), "Mount process timed out. Killing.");
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(m), "Unmounting timed out. Skipping SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mount process timed out. Skipping SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT);
}
break;
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
- log_unit_warning(UNIT(m),"Mount process still around after SIGKILL. Ignoring.");
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(m), "Mount process still around after SIGKILL. Ignoring.");
+ mount_enter_dead_or_mounted(m, MOUNT_FAILURE_TIMEOUT);
break;
default:
@@ -1635,7 +1638,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
}
static void mount_shutdown(Manager *m) {
-
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
@@ -1906,6 +1908,10 @@ static void mount_reset_failed(Unit *u) {
}
static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
+ Mount *m = MOUNT(u);
+
+ assert(m);
+
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}
diff --git a/src/core/mount.h b/src/core/mount.h
index 9f7326ba6a..f81e4217df 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -67,7 +67,7 @@ struct Mount {
bool just_mounted:1;
bool just_changed:1;
- bool reset_cpu_usage:1;
+ bool reset_accounting:1;
bool sloppy_options;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 05175e9552..6d74b8da67 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -31,6 +31,7 @@
#include "dev-setup.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "label.h"
#include "loop-util.h"
#include "loopback-setup.h"
#include "missing.h"
@@ -58,6 +59,7 @@ typedef enum MountMode {
PRIVATE_VAR_TMP,
PRIVATE_DEV,
BIND_DEV,
+ EMPTY_DIR,
SYSFS,
PROCFS,
READONLY,
@@ -100,11 +102,12 @@ static const MountEntry protect_kernel_tunables_table[] = {
{ "/sys/kernel/debug", READONLY, true },
{ "/sys/kernel/tracing", READONLY, true },
{ "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
+ { "/sys/fs/selinux", READWRITE, true },
};
/* ProtectKernelModules= option */
static const MountEntry protect_kernel_modules_table[] = {
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
{ "/lib/modules", INACCESSIBLE, true },
#endif
{ "/usr/lib/modules", INACCESSIBLE, true },
@@ -223,6 +226,28 @@ static int append_access_mounts(MountEntry **p, char **strv, MountMode mode) {
return 0;
}
+static int append_empty_dir_mounts(MountEntry **p, char **strv) {
+ char **i;
+
+ assert(p);
+
+ /* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the
+ * "/private/" boundary directories for DynamicUser=1. */
+
+ STRV_FOREACH(i, strv) {
+
+ *((*p)++) = (MountEntry) {
+ .path_const = *i,
+ .mode = EMPTY_DIR,
+ .ignore = false,
+ .has_prefix = false,
+ .read_only = true,
+ };
+ }
+
+ return 0;
+}
+
static int append_bind_mounts(MountEntry **p, const BindMount *binds, unsigned n) {
unsigned i;
@@ -617,6 +642,8 @@ static int mount_bind_dev(MountEntry *m) {
/* Implements the little brother of mount_private_dev(): simply bind mounts the host's /dev into the service's
* /dev. This is only used when RootDirectory= is set. */
+ (void) mkdir_p_label(mount_entry_path(m), 0755);
+
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /dev is already mounted: %m");
@@ -634,6 +661,8 @@ static int mount_sysfs(MountEntry *m) {
assert(m);
+ (void) mkdir_p_label(mount_entry_path(m), 0755);
+
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /sys is already mounted: %m");
@@ -652,6 +681,8 @@ static int mount_procfs(MountEntry *m) {
assert(m);
+ (void) mkdir_p_label(mount_entry_path(m), 0755);
+
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /proc is already mounted: %m");
@@ -665,6 +696,20 @@ static int mount_procfs(MountEntry *m) {
return 1;
}
+static int mount_empty_dir(MountEntry *m) {
+ assert(m);
+
+ /* First, get rid of everything that is below if there is anything. Then, overmount with our new empty dir */
+
+ (void) mkdir_p_label(mount_entry_path(m), 0755);
+ (void) umount_recursive(mount_entry_path(m), 0);
+
+ if (mount("tmpfs", mount_entry_path(m), "tmpfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, "mode=755") < 0)
+ return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
+
+ return 1;
+}
+
static int mount_entry_chase(
const char *root_directory,
MountEntry *m,
@@ -680,7 +725,9 @@ static int mount_entry_chase(
* chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
* that applies). The result is stored in "location". */
- r = chase_symlinks(path, root_directory, 0, &chased);
+ r = chase_symlinks(path, root_directory,
+ IN_SET(m->mode, BIND_MOUNT, BIND_MOUNT_RECURSIVE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV, BIND_DEV, EMPTY_DIR, SYSFS, PROCFS) ? CHASE_NONEXISTENT : 0,
+ &chased);
if (r == -ENOENT && m->ignore) {
log_debug_errno(r, "Path %s does not exist, ignoring.", path);
return 0;
@@ -702,8 +749,8 @@ static int apply_mount(
const char *tmp_dir,
const char *var_tmp_dir) {
+ bool rbind = true, make = false;
const char *what;
- bool rbind = true;
int r;
assert(m);
@@ -758,14 +805,20 @@ static int apply_mount(
return r;
what = mount_entry_source(m);
+ make = true;
break;
+ case EMPTY_DIR:
+ return mount_empty_dir(m);
+
case PRIVATE_TMP:
what = tmp_dir;
+ make = true;
break;
case PRIVATE_VAR_TMP:
what = var_tmp_dir;
+ make = true;
break;
case PRIVATE_DEV:
@@ -786,8 +839,36 @@ static int apply_mount(
assert(what);
- if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0)
- return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, mount_entry_path(m));
+ if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0) {
+ bool try_again = false;
+ r = -errno;
+
+ if (r == -ENOENT && make) {
+ struct stat st;
+
+ /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
+
+ if (stat(what, &st) >= 0) {
+
+ (void) mkdir_parents(mount_entry_path(m), 0755);
+
+ if (S_ISDIR(st.st_mode))
+ try_again = mkdir(mount_entry_path(m), 0755) >= 0;
+ else
+ try_again = touch(mount_entry_path(m)) >= 0;
+ }
+ }
+
+ if (try_again) {
+ if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0)
+ r = -errno;
+ else
+ r = 0;
+ }
+
+ if (r < 0)
+ return log_debug_errno(r, "Failed to mount %s to %s: %m", what, mount_entry_path(m));
+ }
log_debug("Successfully mounted %s to %s", what, mount_entry_path(m));
return 0;
@@ -839,6 +920,7 @@ static unsigned namespace_calculate_mounts(
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
+ char** empty_directories,
const BindMount *bind_mounts,
unsigned n_bind_mounts,
const char* tmp_dir,
@@ -865,6 +947,7 @@ static unsigned namespace_calculate_mounts(
strv_length(read_write_paths) +
strv_length(read_only_paths) +
strv_length(inaccessible_paths) +
+ strv_length(empty_directories) +
n_bind_mounts +
ns_info->private_dev +
(ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
@@ -881,6 +964,7 @@ int setup_namespace(
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
+ char** empty_directories,
const BindMount *bind_mounts,
unsigned n_bind_mounts,
const char* tmp_dir,
@@ -897,6 +981,7 @@ int setup_namespace(
MountEntry *m, *mounts = NULL;
size_t root_hash_size = 0;
bool make_slave = false;
+ const char *root;
unsigned n_mounts;
int r = 0;
@@ -928,28 +1013,36 @@ int setup_namespace(
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
if (r < 0)
return r;
-
- if (!root_directory) {
- /* Create a mount point for the image, if it's still missing. We use the same mount point for
- * all images, which is safe, since they all live in their own namespaces after all, and hence
- * won't see each other. */
- root_directory = "/run/systemd/unit-root";
- (void) mkdir(root_directory, 0700);
- }
}
+ if (root_directory)
+ root = root_directory;
+ else if (root_image || n_bind_mounts > 0) {
+
+ /* If we are booting from an image, create a mount point for the image, if it's still missing. We use
+ * the same mount point for all images, which is safe, since they all live in their own namespaces
+ * after all, and hence won't see each other. We also use such a root directory whenever there are bind
+ * mounts configured, so that their source mounts are never obstructed by mounts we already applied
+ * while we are applying them. */
+
+ root = "/run/systemd/unit-root";
+ (void) mkdir_label(root, 0700);
+ } else
+ root = NULL;
+
n_mounts = namespace_calculate_mounts(
- root_directory,
+ root,
ns_info,
read_write_paths,
read_only_paths,
inaccessible_paths,
+ empty_directories,
bind_mounts, n_bind_mounts,
tmp_dir, var_tmp_dir,
protect_home, protect_system);
/* Set mount slave mode */
- if (root_directory || n_mounts > 0)
+ if (root || n_mounts > 0)
make_slave = true;
if (n_mounts > 0) {
@@ -966,6 +1059,10 @@ int setup_namespace(
if (r < 0)
goto finish;
+ r = append_empty_dir_mounts(&m, empty_directories);
+ if (r < 0)
+ goto finish;
+
r = append_bind_mounts(&m, bind_mounts, n_bind_mounts);
if (r < 0)
goto finish;
@@ -1018,7 +1115,7 @@ int setup_namespace(
if (r < 0)
goto finish;
- if (namespace_info_mount_apivfs(root_directory, ns_info)) {
+ if (namespace_info_mount_apivfs(root, ns_info)) {
r = append_static_mounts(&m, apivfs_table, ELEMENTSOF(apivfs_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
@@ -1027,14 +1124,14 @@ int setup_namespace(
assert(mounts + n_mounts == m);
/* Prepend the root directory where that's necessary */
- r = prefix_where_needed(mounts, n_mounts, root_directory);
+ r = prefix_where_needed(mounts, n_mounts, root);
if (r < 0)
goto finish;
qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
drop_duplicates(mounts, &n_mounts);
- drop_outside_root(root_directory, mounts, &n_mounts);
+ drop_outside_root(root, mounts, &n_mounts);
drop_inaccessible(mounts, &n_mounts);
drop_nop(mounts, &n_mounts);
}
@@ -1054,32 +1151,43 @@ int setup_namespace(
}
/* Try to set up the new root directory before mounting anything there */
- if (root_directory)
- (void) base_filesystem_create(root_directory, UID_INVALID, GID_INVALID);
+ if (root)
+ (void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
if (root_image) {
- r = dissected_image_mount(dissected_image, root_directory, dissect_image_flags);
+ /* A root image is specified, mount it to the right place */
+ r = dissected_image_mount(dissected_image, root, dissect_image_flags);
if (r < 0)
goto finish;
- r = decrypted_image_relinquish(decrypted_image);
- if (r < 0)
- goto finish;
+ if (decrypted_image) {
+ r = decrypted_image_relinquish(decrypted_image);
+ if (r < 0)
+ goto finish;
+ }
loop_device_relinquish(loop_device);
} else if (root_directory) {
- /* Turn directory into bind mount, if it isn't one yet */
- r = path_is_mount_point(root_directory, NULL, AT_SYMLINK_FOLLOW);
+ /* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
+ r = path_is_mount_point(root, NULL, AT_SYMLINK_FOLLOW);
if (r < 0)
goto finish;
if (r == 0) {
- if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0) {
+ if (mount(root, root, NULL, MS_BIND|MS_REC, NULL) < 0) {
r = -errno;
goto finish;
}
}
+
+ } else if (root) {
+
+ /* Let's mount the main root directory to the root directory to use */
+ if (mount("/", root, NULL, MS_BIND|MS_REC, NULL) < 0) {
+ r = -errno;
+ goto finish;
+ }
}
if (n_mounts > 0) {
@@ -1097,7 +1205,7 @@ int setup_namespace(
/* First round, add in all special mounts we need */
for (m = mounts; m < mounts + n_mounts; ++m) {
- r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir);
+ r = apply_mount(root, m, tmp_dir, var_tmp_dir);
if (r < 0)
goto finish;
}
@@ -1116,9 +1224,9 @@ int setup_namespace(
}
}
- if (root_directory) {
+ if (root) {
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
- r = mount_move_root(root_directory);
+ r = mount_move_root(root);
if (r < 0)
goto finish;
}
diff --git a/src/core/namespace.h b/src/core/namespace.h
index f54954bd86..da8d85dbc5 100644
--- a/src/core/namespace.h
+++ b/src/core/namespace.h
@@ -69,6 +69,7 @@ int setup_namespace(
char **read_write_paths,
char **read_only_paths,
char **inaccessible_paths,
+ char **empty_directories,
const BindMount *bind_mounts,
unsigned n_bind_mounts,
const char *tmp_dir,
diff --git a/src/core/path.c b/src/core/path.c
index 83f794be89..44831f5803 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -97,7 +97,7 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
r = inotify_add_watch(s->inotify_fd, s->path, flags);
if (r < 0) {
- if (errno == EACCES || errno == ENOENT) {
+ if (IN_SET(errno, EACCES, ENOENT)) {
if (cut)
*cut = tmp;
break;
@@ -168,14 +168,14 @@ int path_spec_fd_event(PathSpec *s, uint32_t revents) {
l = read(s->inotify_fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_error_errno(errno, "Failed to read inotify event: %m");
}
FOREACH_INOTIFY_EVENT(e, buffer, l) {
- if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
+ if (IN_SET(s->type, PATH_CHANGED, PATH_MODIFIED) &&
s->primary_wd == e->wd)
r = 1;
}
@@ -224,7 +224,7 @@ static bool path_spec_check_good(PathSpec *s, bool initial) {
static void path_spec_mkdir(PathSpec *s, mode_t mode) {
int r;
- if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
+ if (IN_SET(s->type, PATH_EXISTS, PATH_EXISTS_GLOB))
return;
r = mkdir_p_label(s->path, mode);
@@ -441,8 +441,7 @@ static int path_coldplug(Unit *u) {
if (p->deserialized_state != p->state) {
- if (p->deserialized_state == PATH_WAITING ||
- p->deserialized_state == PATH_RUNNING)
+ if (IN_SET(p->deserialized_state, PATH_WAITING, PATH_RUNNING))
path_enter_waiting(p, true, true);
else
path_set_state(p, p->deserialized_state);
@@ -457,6 +456,9 @@ static void path_enter_dead(Path *p, PathResult f) {
if (p->result == PATH_SUCCESS)
p->result = f;
+ if (p->result != PATH_SUCCESS)
+ log_unit_warning(UNIT(p), "Failed with result '%s'.", path_result_to_string(p->result));
+
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
}
@@ -563,7 +565,7 @@ static int path_start(Unit *u) {
int r;
assert(p);
- assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
+ assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
trigger = UNIT_TRIGGER(u);
if (!trigger || trigger->load_state != UNIT_LOADED) {
@@ -593,7 +595,7 @@ static int path_stop(Unit *u) {
Path *p = PATH(u);
assert(p);
- assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
+ assert(IN_SET(p->state, PATH_WAITING, PATH_RUNNING));
path_enter_dead(p, PATH_SUCCESS);
return 1;
@@ -667,8 +669,7 @@ static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
p = PATH(s->unit);
- if (p->state != PATH_WAITING &&
- p->state != PATH_RUNNING)
+ if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
return 0;
/* log_debug("inotify wakeup on %s.", u->id); */
diff --git a/src/core/scope.c b/src/core/scope.c
index a1d5c1cfd5..4cd5e3dd2a 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -253,6 +253,9 @@ static void scope_enter_dead(Scope *s, ScopeResult f) {
if (s->result == SCOPE_SUCCESS)
s->result = f;
+ if (s->result != SCOPE_SUCCESS)
+ log_unit_warning(UNIT(s), "Failed with result '%s'.", scope_result_to_string(s->result));
+
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
}
@@ -319,8 +322,7 @@ static int scope_start(Unit *u) {
return -EPERM;
/* We can't fulfill this right now, please try again later */
- if (s->state == SCOPE_STOP_SIGTERM ||
- s->state == SCOPE_STOP_SIGKILL)
+ if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
return -EAGAIN;
assert(s->state == SCOPE_DEAD);
@@ -333,7 +335,8 @@ static int scope_start(Unit *u) {
return r;
(void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_usage(u);
+ (void) unit_reset_cpu_accounting(u);
+ (void) unit_reset_ip_accounting(u);
r = unit_attach_pids_to_cgroup(u);
if (r < 0) {
@@ -353,12 +356,10 @@ static int scope_stop(Unit *u) {
assert(s);
- if (s->state == SCOPE_STOP_SIGTERM ||
- s->state == SCOPE_STOP_SIGKILL)
+ if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
return 0;
- assert(s->state == SCOPE_RUNNING ||
- s->state == SCOPE_ABANDONED);
+ assert(IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED));
scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
return 1;
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 0f8a2d68e2..2db4189401 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -19,13 +19,13 @@
#include "selinux-access.h"
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <errno.h>
#include <selinux/avc.h>
#include <selinux/selinux.h>
#include <stdio.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#endif
@@ -112,7 +112,7 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_list ap;
const char *fmt2;
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
int fd;
fd = get_audit_fd();
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index f46370d020..1f6a518a61 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -26,7 +26,7 @@
int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#define mac_selinux_access_check(message, permission, error) \
mac_selinux_generic_access_check((message), NULL, (permission), (error))
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index 527aa8add0..60361a5638 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -21,7 +21,7 @@
#include <stdio.h>
#include <unistd.h>
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
@@ -32,7 +32,7 @@
#include "string-util.h"
#include "util.h"
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
_printf_(2,3)
static int null_log(int type, const char *fmt, ...) {
return 0;
@@ -41,7 +41,7 @@ static int null_log(int type, const char *fmt, ...) {
int mac_selinux_setup(bool *loaded_policy) {
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
int enforce = 0;
usec_t before_load, after_load;
char *con;
diff --git a/src/core/service.c b/src/core/service.c
index 0ddf9352f6..156d9955f1 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -21,6 +21,8 @@
#include <signal.h>
#include <unistd.h>
+#include "sd-messages.h"
+
#include "alloc-util.h"
#include "async.h"
#include "bus-error.h"
@@ -158,7 +160,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
if (pid <= 1)
return -EINVAL;
- if (pid == getpid())
+ if (pid == getpid_cached())
return -EINVAL;
if (s->main_pid == pid && s->main_pid_known)
@@ -172,7 +174,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid = pid;
s->main_pid_known = true;
- if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) {
+ if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid_cached()) {
log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
s->main_pid_alien = true;
} else
@@ -217,7 +219,7 @@ static void service_start_watchdog(Service *s) {
assert(s);
watchdog_usec = service_get_watchdog_usec(s);
- if (watchdog_usec == 0 || watchdog_usec == USEC_INFINITY)
+ if (IN_SET(watchdog_usec, 0, USEC_INFINITY))
return;
if (s->watchdog_event_source) {
@@ -530,7 +532,7 @@ static int service_verify(Service *s) {
if (s->bus_name && s->type != SERVICE_DBUS)
log_unit_warning(UNIT(s), "Service has a D-Bus service name specified, but is not of type dbus. Ignoring.");
- if (s->exec_context.pam_name && !(s->kill_context.kill_mode == KILL_CONTROL_GROUP || s->kill_context.kill_mode == KILL_MIXED)) {
+ if (s->exec_context.pam_name && !IN_SET(s->kill_context.kill_mode, KILL_CONTROL_GROUP, KILL_MIXED)) {
log_unit_error(UNIT(s), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.");
return -EINVAL;
}
@@ -628,7 +630,7 @@ static int service_setup_bus_name(Service *s) {
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
}
- /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */
+ /* We always want to be ordered against dbus.socket if both are in the transaction. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
@@ -815,6 +817,8 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
"%sFile Descriptor Store Current: %u\n",
prefix, s->n_fd_store_max,
prefix, s->n_fd_store);
+
+ cgroup_context_dump(&s->cgroup_context, f, prefix);
}
static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
@@ -1284,7 +1288,6 @@ static int service_spawn(
_cleanup_strv_free_ char **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ int *fds = NULL;
unsigned n_storage_fds = 0, n_socket_fds = 0, n_env = 0;
- const char *path;
pid_t pid;
ExecParameters exec_params = {
@@ -1303,15 +1306,16 @@ static int service_spawn(
if (flags & EXEC_IS_CONTROL) {
/* If this is a control process, mask the permissions/chroot application if this is requested. */
if (s->permissions_start_only)
- exec_params.flags &= ~EXEC_APPLY_PERMISSIONS;
+ exec_params.flags &= ~EXEC_APPLY_SANDBOXING;
if (s->root_directory_start_only)
exec_params.flags &= ~EXEC_APPLY_CHROOT;
}
(void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
+ if (s->reset_accounting) {
+ (void) unit_reset_cpu_accounting(UNIT(s));
+ (void) unit_reset_ip_accounting(UNIT(s));
+ s->reset_accounting = false;
}
r = unit_setup_exec_runtime(UNIT(s));
@@ -1351,7 +1355,7 @@ static int service_spawn(
return -ENOMEM;
if (MANAGER_IS_USER(UNIT(s)->manager))
- if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
+ if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid_cached()) < 0)
return -ENOMEM;
if (s->socket_fd >= 0) {
@@ -1410,28 +1414,31 @@ static int service_spawn(
}
}
- final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
+ manager_set_exec_params(UNIT(s)->manager, &exec_params);
+ unit_set_exec_params(UNIT(s), &exec_params);
+
+ final_env = strv_env_merge(2, exec_params.environment, our_env, NULL);
if (!final_env)
return -ENOMEM;
if ((flags & EXEC_IS_CONTROL) && UNIT(s)->cgroup_path) {
- path = strjoina(UNIT(s)->cgroup_path, "/control");
- (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
- } else
- path = UNIT(s)->cgroup_path;
+ exec_params.cgroup_path = strjoina(UNIT(s)->cgroup_path, "/control");
+ (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, exec_params.cgroup_path);
+ }
+
+ /* System services should get a new keyring by default. */
+ SET_FLAG(exec_params.flags, EXEC_NEW_KEYRING, MANAGER_IS_SYSTEM(UNIT(s)->manager));
+
+ /* System D-Bus needs nss-systemd disabled, so that we don't deadlock */
+ SET_FLAG(exec_params.flags, EXEC_NSS_BYPASS_BUS,
+ MANAGER_IS_SYSTEM(UNIT(s)->manager) && unit_has_name(UNIT(s), SPECIAL_DBUS_SERVICE));
- exec_params.flags |= MANAGER_IS_SYSTEM(UNIT(s)->manager) ? EXEC_NEW_KEYRING : 0;
exec_params.argv = c->argv;
exec_params.environment = final_env;
exec_params.fds = fds;
exec_params.fd_names = fd_names;
exec_params.n_storage_fds = n_storage_fds;
exec_params.n_socket_fds = n_socket_fds;
- exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
@@ -1462,8 +1469,7 @@ static int service_spawn(
static int main_pid_good(Service *s) {
assert(s);
- /* Returns 0 if the pid is dead, 1 if it is good, -1 if we
- * don't know */
+ /* Returns 0 if the pid is dead, > 0 if it is good, < 0 if we don't know */
/* If we know the pid file, then let's just check if it is
* still valid */
@@ -1484,9 +1490,13 @@ static int main_pid_good(Service *s) {
return -EAGAIN;
}
-_pure_ static int control_pid_good(Service *s) {
+static int control_pid_good(Service *s) {
assert(s);
+ /* Returns 0 if the control PID is dead, > 0 if it is good. We never actually return < 0 here, but in order to
+ * make this function as similar as possible to main_pid_good() and cgroup_good(), we pretend that < 0 also
+ * means: we can't figure it out. */
+
return s->control_pid > 0;
}
@@ -1495,6 +1505,9 @@ static int cgroup_good(Service *s) {
assert(s);
+ /* Returns 0 if the cgroup is empty or doesn't exist, > 0 if it is exists and is populated, < 0 if we can't
+ * figure it out */
+
if (!UNIT(s)->cgroup_path)
return 0;
@@ -1502,7 +1515,7 @@ static int cgroup_good(Service *s) {
if (r < 0)
return r;
- return !r;
+ return r == 0;
}
static bool service_shall_restart(Service *s) {
@@ -1548,19 +1561,38 @@ static bool service_shall_restart(Service *s) {
}
}
+static bool service_will_restart(Service *s) {
+ assert(s);
+
+ if (s->state == SERVICE_AUTO_RESTART)
+ return true;
+ if (!UNIT(s)->job)
+ return false;
+ if (UNIT(s)->job->type == JOB_START)
+ return true;
+ return false;
+}
+
static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
int r;
+
assert(s);
+ /* If there's a stop job queued before we enter the DEAD state, we shouldn't act on Restart=, in order to not
+ * undo what has already been enqueued. */
+ if (unit_stop_pending(UNIT(s)))
+ allow_restart = false;
+
if (s->result == SERVICE_SUCCESS)
s->result = f;
+ if (s->result != SERVICE_SUCCESS)
+ log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
+
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
- if (s->result != SERVICE_SUCCESS) {
- log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result));
+ if (s->result != SERVICE_SUCCESS)
emergency_action(UNIT(s)->manager, s->emergency_action, UNIT(s)->reboot_arg, "service failed");
- }
if (allow_restart && service_shall_restart(s)) {
@@ -1569,7 +1601,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
goto fail;
service_set_state(s, SERVICE_AUTO_RESTART);
- }
+ } else
+ /* If we shan't restart, then flush out the restart counter. But don't do that immediately, so that the
+ * user can still introspect the counter. Do so on the next start. */
+ s->flush_n_restarts = true;
/* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
s->forbid_restart = false;
@@ -1578,8 +1613,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
exec_runtime_destroy(s->exec_runtime);
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- /* Also, remove the runtime directory */
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
+ if (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_NO ||
+ (s->exec_context.runtime_directory_preserve_mode == EXEC_PRESERVE_RESTART && !service_will_restart(s)))
+ /* Also, remove the runtime directory */
+ exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
/* Get rid of the IPC bits of the user */
unit_unref_uid_gid(UNIT(s), true);
@@ -1617,7 +1654,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1669,7 +1706,6 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
s->main_pid,
s->control_pid,
s->main_pid_alien);
-
if (r < 0)
goto fail;
@@ -1728,7 +1764,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1807,7 +1843,7 @@ static void service_enter_start_post(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1824,13 +1860,39 @@ fail:
}
static void service_kill_control_processes(Service *s) {
- char *p;
+ int r;
- if (!UNIT(s)->cgroup_path)
- return;
+ assert(s);
+
+ if (s->control_pid > 0) {
+ r = kill_and_sigcont(s->control_pid, SIGKILL);
+ if (r < 0) {
+ _cleanup_free_ char *comm = NULL;
- p = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, CGROUP_SIGCONT|CGROUP_IGNORE_SELF|CGROUP_REMOVE, NULL, NULL, NULL);
+ (void) get_process_comm(s->control_pid, &comm);
+
+ log_unit_debug_errno(UNIT(s), r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m",
+ s->control_pid, strna(comm));
+ }
+ }
+
+ if (UNIT(s)->cgroup_path) {
+ _cleanup_set_free_ Set *pid_set = NULL;
+ char *p;
+
+ if (s->control_pid > 0) {
+ r = set_make(&pid_set, PID_TO_PTR(s->control_pid), NULL);
+ if (r < 0) {
+ log_oom();
+ return;
+ }
+ }
+
+ p = strjoina(UNIT(s)->cgroup_path, "/control");
+ r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, CGROUP_SIGCONT|CGROUP_IGNORE_SELF|CGROUP_REMOVE, pid_set, NULL, NULL);
+ if (r < 0)
+ log_unit_debug_errno(UNIT(s), r, "Failed to send SIGKILL to processes of control group %s: %m", p);
+ }
}
static void service_enter_start(Service *s) {
@@ -1885,7 +1947,7 @@ static void service_enter_start(Service *s) {
r = service_spawn(s,
c,
timeout,
- EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
+ EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
&pid);
if (r < 0)
goto fail;
@@ -1944,7 +2006,7 @@ static void service_enter_start_pre(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1985,11 +2047,27 @@ static void service_enter_restart(Service *s) {
if (r < 0)
goto fail;
+ /* Count the jobs we enqueue for restarting. This counter is maintained as long as the unit isn't fully
+ * stopped, i.e. as long as it remains up or remains in auto-start states. The use can reset the counter
+ * explicitly however via the usual "systemctl reset-failure" logic. */
+ s->n_restarts ++;
+ s->flush_n_restarts = false;
+
+ log_struct(LOG_INFO,
+ "MESSAGE_ID=" SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR,
+ LOG_UNIT_ID(UNIT(s)),
+ LOG_UNIT_INVOCATION_ID(UNIT(s)),
+ LOG_UNIT_MESSAGE(UNIT(s), "Scheduled restart job, restart counter is at %u.", s->n_restarts),
+ "N_RESTARTS=%u", s->n_restarts,
+ NULL);
+
+ /* Notify clients about changed restart counter */
+ unit_add_to_dbus_queue(UNIT(s));
+
/* Note that we stay in the SERVICE_AUTO_RESTART state here,
* it will be canceled as part of the service_stop() call that
* is executed as part of JOB_RESTART. */
- log_unit_debug(UNIT(s), "Scheduled restart job.");
return;
fail:
@@ -1998,10 +2076,18 @@ fail:
}
static void service_enter_reload_by_notify(Service *s) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
assert(s);
service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec));
service_set_state(s, SERVICE_RELOAD);
+
+ /* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
+ r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
+ if (r < 0)
+ log_unit_warning(UNIT(s), "Failed to schedule propagation of reload: %s", bus_error_message(&error, -r));
}
static void service_enter_reload(Service *s) {
@@ -2019,7 +2105,7 @@ static void service_enter_reload(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
&s->control_pid);
if (r < 0)
goto fail;
@@ -2057,7 +2143,7 @@ static void service_run_next_control(Service *s) {
r = service_spawn(s,
s->control_command,
timeout,
- EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
+ EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
(IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
(IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
&s->control_pid);
@@ -2095,7 +2181,7 @@ static void service_run_next_main(Service *s) {
r = service_spawn(s,
s->main_command,
s->timeout_start_usec,
- EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
+ EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
&pid);
if (r < 0)
goto fail;
@@ -2154,7 +2240,7 @@ static int service_start(Unit *u) {
s->main_pid_known = false;
s->main_pid_alien = false;
s->forbid_restart = false;
- s->reset_cpu_usage = true;
+ s->reset_accounting = true;
s->status_text = mfree(s->status_text);
s->status_errno = 0;
@@ -2164,6 +2250,12 @@ static int service_start(Unit *u) {
s->watchdog_override_enable = false;
s->watchdog_override_usec = 0;
+ /* This is not an automatic restart? Flush the restart counter then */
+ if (s->flush_n_restarts) {
+ s->n_restarts = 0;
+ s->flush_n_restarts = false;
+ }
+
service_enter_start_pre(s);
return 1;
}
@@ -2206,7 +2298,7 @@ static int service_reload(Unit *u) {
assert(s);
- assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
+ assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
service_enter_reload(s);
return 1;
@@ -2316,6 +2408,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner);
+ unit_serialize_item_format(u, f, "n-restarts", "%u", s->n_restarts);
+ unit_serialize_item(u, f, "flush-n-restarts", yes_no(s->flush_n_restarts));
+
r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
if (r < 0)
return r;
@@ -2681,6 +2776,18 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
r = service_deserialize_exec_command(u, key, value);
if (r < 0)
log_unit_debug_errno(u, r, "Failed to parse serialized command \"%s\": %m", value);
+
+ } else if (streq(key, "n-restarts")) {
+ r = safe_atou(value, &s->n_restarts);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse serialized restart counter '%s': %m", value);
+
+ } else if (streq(key, "flush-n-restarts")) {
+ r = parse_boolean(value);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to parse serialized flush restart counter setting '%s': %m", value);
+ else
+ s->flush_n_restarts = r;
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2722,7 +2829,7 @@ static int service_retry_pid_file(Service *s) {
int r;
assert(s->pid_file);
- assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
+ assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
r = service_load_pid_file(s, false);
if (r < 0)
@@ -2793,7 +2900,7 @@ static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events,
assert(s);
assert(fd >= 0);
- assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
+ assert(IN_SET(s->state, SERVICE_START, SERVICE_START_POST));
assert(s->pid_file_pathspec);
assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
@@ -2832,7 +2939,9 @@ static void service_notify_cgroup_empty_event(Unit *u) {
* SIGCHLD for. */
case SERVICE_START:
- if (s->type == SERVICE_NOTIFY) {
+ if (s->type == SERVICE_NOTIFY &&
+ main_pid_good(s) == 0 &&
+ control_pid_good(s) == 0) {
/* No chance of getting a ready notification anymore */
service_enter_stop_post(s, SERVICE_FAILURE_PROTOCOL);
break;
@@ -2841,7 +2950,10 @@ static void service_notify_cgroup_empty_event(Unit *u) {
/* Fall through */
case SERVICE_START_POST:
- if (s->pid_file_pathspec) {
+ if (s->pid_file_pathspec &&
+ main_pid_good(s) == 0 &&
+ control_pid_good(s) == 0) {
+
/* Give up hoping for the daemon to write its PID file */
log_unit_warning(u, "Daemon never wrote its PID file. Failing.");
@@ -2862,7 +2974,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
- if (main_pid_good(s) <= 0 && !control_pid_good(s))
+ if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
service_enter_stop_post(s, SERVICE_SUCCESS);
break;
@@ -2870,7 +2982,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
case SERVICE_STOP_POST:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
- if (main_pid_good(s) <= 0 && !control_pid_good(s))
+ if (main_pid_good(s) <= 0 && control_pid_good(s) <= 0)
service_enter_dead(s, SERVICE_SUCCESS, true);
break;
@@ -2917,7 +3029,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->main_command->exec_status = s->main_exec_status;
- if (s->main_command->ignore)
+ if (s->main_command->flags & EXEC_COMMAND_IGNORE_FAILURE)
f = SERVICE_SUCCESS;
} else if (s->exec_command[SERVICE_EXEC_START]) {
@@ -2925,7 +3037,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
* ignore the return value if this was
* configured for the starter process */
- if (s->exec_command[SERVICE_EXEC_START]->ignore)
+ if (s->exec_command[SERVICE_EXEC_START]->flags & EXEC_COMMAND_IGNORE_FAILURE)
f = SERVICE_SUCCESS;
}
@@ -2945,6 +3057,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"EXIT_CODE=%s", sigchld_code_to_string(code),
"EXIT_STATUS=%i", status,
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
NULL);
if (s->result == SERVICE_SUCCESS)
@@ -2952,6 +3065,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (s->main_command &&
s->main_command->command_next &&
+ s->type == SERVICE_ONESHOT &&
f == SERVICE_SUCCESS) {
/* There is another command to *
@@ -2989,8 +3103,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
* has been received */
if (f != SERVICE_SUCCESS)
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
- else if (!s->remain_after_exit)
- /* The service has never been active */
+ else if (!s->remain_after_exit || s->notify_access == NOTIFY_MAIN)
+ /* The service has never been and will never be active */
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL);
break;
}
@@ -3005,7 +3119,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
- if (!control_pid_good(s))
+ if (control_pid_good(s) <= 0)
service_enter_stop_post(s, f);
/* If there is still a control process, wait for that first */
@@ -3015,7 +3129,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
- if (!control_pid_good(s))
+ if (control_pid_good(s) <= 0)
service_enter_dead(s, f, true);
break;
@@ -3030,7 +3144,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
- if (s->control_command->ignore)
+ if (s->control_command->flags & EXEC_COMMAND_IGNORE_FAILURE)
f = SERVICE_SUCCESS;
}
@@ -3096,7 +3210,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
r = service_load_pid_file(s, !has_start_post);
if (!has_start_post && r < 0) {
r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
+ if (r < 0 || cgroup_good(s) == 0)
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_PROTOCOL);
break;
}
@@ -3118,7 +3232,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
r = service_load_pid_file(s, true);
if (r < 0) {
r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
+ if (r < 0 || cgroup_good(s) == 0)
service_enter_stop(s, SERVICE_FAILURE_PROTOCOL);
break;
}
@@ -3179,7 +3293,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* If the PID set is empty now, then let's finish this off
(On unified we use proper notifications) */
if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) == 0 && set_isempty(u->pids))
- service_notify_cgroup_empty_event(u);
+ unit_add_to_cgroup_empty_queue(u);
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
@@ -3424,9 +3538,7 @@ static void service_notify_message(
}
if (!streq_ptr(s->status_text, t)) {
-
free_and_replace(s->status_text, t);
-
notify_dbus = true;
}
}
@@ -3536,10 +3648,11 @@ static void service_bus_name_owner_change(
} else if (new_owner &&
s->main_pid <= 0 &&
- (s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RUNNING ||
- s->state == SERVICE_RELOAD)) {
+ IN_SET(s->state,
+ SERVICE_START,
+ SERVICE_START_POST,
+ SERVICE_RUNNING,
+ SERVICE_RELOAD)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
pid_t pid;
@@ -3615,11 +3728,15 @@ static void service_reset_failed(Unit *u) {
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
+ s->n_restarts = 0;
+ s->flush_n_restarts = false;
}
static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
Service *s = SERVICE(u);
+ assert(s);
+
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
}
diff --git a/src/core/service.h b/src/core/service.h
index f4ba604f69..16b700637c 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -165,7 +165,7 @@ struct Service {
bool forbid_restart:1;
bool start_timeout_defined:1;
- bool reset_cpu_usage:1;
+ bool reset_accounting:1;
char *bus_name;
char *bus_name_owner; /* unique name of the current owner */
@@ -193,6 +193,9 @@ struct Service {
int stdin_fd;
int stdout_fd;
int stderr_fd;
+
+ unsigned n_restarts;
+ bool flush_n_restarts;
};
extern const UnitVTable service_vtable;
diff --git a/src/core/show-status.c b/src/core/show-status.c
index 65f9cb888a..8c94573844 100644
--- a/src/core/show-status.c
+++ b/src/core/show-status.c
@@ -93,21 +93,21 @@ int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char
}
if (prev_ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+ iovec[n++] = IOVEC_MAKE_STRING("\r" ANSI_ERASE_TO_END_OF_LINE);
prev_ephemeral = ephemeral;
if (status) {
if (!isempty(status)) {
- IOVEC_SET_STRING(iovec[n++], "[");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "] ");
+ iovec[n++] = IOVEC_MAKE_STRING("[");
+ iovec[n++] = IOVEC_MAKE_STRING(status);
+ iovec[n++] = IOVEC_MAKE_STRING("] ");
} else
- IOVEC_SET_STRING(iovec[n++], status_indent);
+ iovec[n++] = IOVEC_MAKE_STRING(status_indent);
}
- IOVEC_SET_STRING(iovec[n++], s);
+ iovec[n++] = IOVEC_MAKE_STRING(s);
if (!ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\n");
+ iovec[n++] = IOVEC_MAKE_STRING("\n");
if (writev(fd, iovec, n) < 0)
return -errno;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index a7d5e57936..6d1cc3120a 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -180,7 +180,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (getpid() != 1) {
+ if (getpid_cached() != 1) {
log_error("Not executed by init (PID 1).");
r = -EPERM;
goto error;
diff --git a/src/core/slice.c b/src/core/slice.c
index ed5d3fd701..b15f751c82 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -222,7 +222,8 @@ static int slice_start(Unit *u) {
return r;
(void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_usage(u);
+ (void) unit_reset_cpu_accounting(u);
+ (void) unit_reset_ip_accounting(u);
slice_set_state(t, SLICE_ACTIVE);
return 1;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index adf2293142..9cd539f3d3 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -36,7 +36,7 @@
#include "string-util.h"
#include "util.h"
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
static int write_access2_rules(const char* srcdir) {
_cleanup_close_ int load2_fd = -1, change_fd = -1;
@@ -246,7 +246,7 @@ static int write_netlabel_rules(const char* srcdir) {
FOREACH_LINE(buf, policy,
log_error_errno(errno, "Failed to read line from %s: %m",
entry->d_name)) {
- if (!fputs(buf, dst)) {
+ if (!fputs_unlocked(buf, dst)) {
if (r == 0)
r = -EINVAL;
log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
@@ -316,7 +316,7 @@ static int write_onlycap_list(void) {
int mac_smack_setup(bool *loaded_policy) {
-#ifdef HAVE_SMACK
+#if ENABLE_SMACK
int r;
diff --git a/src/core/socket.c b/src/core/socket.c
index 7843f7e867..3fc478e852 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -29,6 +29,7 @@
#include <linux/sctp.h>
#include "alloc-util.h"
+#include "bpf-firewall.h"
#include "bus-error.h"
#include "bus-util.h"
#include "copy.h"
@@ -37,6 +38,8 @@
#include "exit-status.h"
#include "fd-util.h"
#include "format-util.h"
+#include "fs-util.h"
+#include "in-addr-util.h"
#include "io-util.h"
#include "label.h"
#include "log.h"
@@ -56,7 +59,6 @@
#include "unit-name.h"
#include "unit.h"
#include "user-util.h"
-#include "in-addr-util.h"
struct SocketPeer {
unsigned n_ref;
@@ -397,12 +399,12 @@ static int socket_add_extras(Socket *s) {
r = unit_add_exec_dependencies(u, &s->exec_context);
if (r < 0)
return r;
-
- r = unit_set_default_slice(u);
- if (r < 0)
- return r;
}
+ r = unit_set_default_slice(u);
+ if (r < 0)
+ return r;
+
r = socket_add_default_dependencies(s);
if (r < 0)
return r;
@@ -852,6 +854,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
exec_command_dump_list(s->exec_command[c], f, prefix2);
}
+
+ cgroup_context_dump(&s->cgroup_context, f, prefix);
}
static int instance_from_socket(int fd, unsigned nr, char **instance) {
@@ -1171,7 +1175,7 @@ static int fifo_address_create(
assert(path);
- mkdir_parents_label(path, directory_mode);
+ (void) mkdir_parents_label(path, directory_mode);
r = mac_selinux_create_file_prepare(path, S_IFIFO);
if (r < 0)
@@ -1321,6 +1325,7 @@ static int mq_address_create(
static int socket_symlink(Socket *s) {
const char *p;
char **i;
+ int r;
assert(s);
@@ -1328,8 +1333,23 @@ static int socket_symlink(Socket *s) {
if (!p)
return 0;
- STRV_FOREACH(i, s->symlinks)
- symlink_label(p, *i);
+ STRV_FOREACH(i, s->symlinks) {
+ (void) mkdir_parents_label(*i, s->directory_mode);
+
+ r = symlink_idempotent(p, *i);
+
+ if (r == -EEXIST && s->remove_on_stop) {
+ /* If there's already something where we want to create the symlink, and the destructive
+ * RemoveOnStop= mode is set, then we might as well try to remove what already exists and try
+ * again. */
+
+ if (unlink(*i) >= 0)
+ r = symlink_idempotent(p, *i);
+ }
+
+ if (r < 0)
+ log_unit_warning_errno(UNIT(s), r, "Failed to create symlink %s → %s, ignoring: %m", p, *i);
+ }
return 0;
}
@@ -1424,7 +1444,7 @@ static int socket_determine_selinux_label(Socket *s, char **ret) {
goto no_label;
r = mac_selinux_get_create_label_from_exe(c->path, ret);
- if (r == -EPERM || r == -EOPNOTSUPP)
+ if (IN_SET(r, -EPERM, -EOPNOTSUPP))
goto no_label;
}
@@ -1435,6 +1455,102 @@ no_label:
return 0;
}
+static int socket_address_listen_do(
+ Socket *s,
+ const SocketAddress *address,
+ const char *label) {
+
+ assert(s);
+ assert(address);
+
+ return socket_address_listen(
+ address,
+ SOCK_CLOEXEC|SOCK_NONBLOCK,
+ s->backlog,
+ s->bind_ipv6_only,
+ s->bind_to_device,
+ s->reuse_port,
+ s->free_bind,
+ s->transparent,
+ s->directory_mode,
+ s->socket_mode,
+ label);
+}
+
+static int socket_address_listen_in_cgroup(
+ Socket *s,
+ const SocketAddress *address,
+ const char *label) {
+
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ int fd, r;
+ pid_t pid;
+
+ assert(s);
+ assert(address);
+
+ /* This is a wrapper around socket_address_listen(), that forks off a helper process inside the socket's cgroup
+ * in which the socket is actually created. This way we ensure the socket is actually properly attached to the
+ * unit's cgroup for the purpose of BPF filtering and such. */
+
+ if (!IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6))
+ goto shortcut; /* BPF filtering only applies to IPv4 + IPv6, shortcut things for other protocols */
+
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0) /* If BPF firewalling isn't supported anyway — there's no point in this forking complexity */
+ goto shortcut;
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
+ return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
+
+ r = unit_fork_helper_process(UNIT(s), &pid);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to fork off listener stub process: %m");
+ if (r == 0) {
+ /* Child */
+
+ pair[0] = safe_close(pair[0]);
+
+ fd = socket_address_listen_do(s, address, label);
+ if (fd < 0) {
+ log_unit_error_errno(UNIT(s), fd, "Failed to create listening socket: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ r = send_one_fd(pair[1], fd, 0);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to send listening socket to parent: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+ fd = receive_one_fd(pair[0], 0);
+
+ /* We synchronously wait for the helper, as it shouldn't be slow */
+ r = wait_for_terminate_and_warn("listen-cgroup-helper", pid, false);
+ if (r < 0) {
+ safe_close(fd);
+ return r;
+ }
+
+ if (fd < 0)
+ return log_unit_error_errno(UNIT(s), fd, "Failed to receive listening socket: %m");
+
+ return fd;
+
+shortcut:
+ fd = socket_address_listen_do(s, address, label);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to create listening socket: %m");
+
+ return fd;
+}
+
static int socket_open_fds(Socket *s) {
_cleanup_(mac_selinux_freep) char *label = NULL;
bool know_label = false;
@@ -1478,18 +1594,7 @@ static int socket_open_fds(Socket *s) {
break;
}
- r = socket_address_listen(
- &p->address,
- SOCK_CLOEXEC|SOCK_NONBLOCK,
- s->backlog,
- s->bind_ipv6_only,
- s->bind_to_device,
- s->reuse_port,
- s->free_bind,
- s->transparent,
- s->directory_mode,
- s->socket_mode,
- label);
+ r = socket_address_listen_in_cgroup(s, &p->address, label);
if (r < 0)
goto rollback;
@@ -1762,7 +1867,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -1773,9 +1878,10 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
assert(_pid);
(void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
+ if (s->reset_accounting) {
+ (void) unit_reset_cpu_accounting(UNIT(s));
+ (void) unit_reset_ip_accounting(UNIT(s));
+ s->reset_accounting = false;
}
r = unit_setup_exec_runtime(UNIT(s));
@@ -1790,13 +1896,10 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
if (r < 0)
return r;
+ manager_set_exec_params(UNIT(s)->manager, &exec_params);
+ unit_set_exec_params(UNIT(s), &exec_params);
+
exec_params.argv = c->argv;
- exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(s)->cgroup_path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
r = exec_spawn(UNIT(s),
c,
@@ -1814,6 +1917,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
return r;
*_pid = pid;
+
return 0;
}
@@ -1828,27 +1932,23 @@ static int socket_chown(Socket *s, pid_t *_pid) {
/* We have to resolve the user names out-of-process, hence
* let's fork here. It's messy, but well, what can we do? */
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- SocketPort *p;
+ r = unit_fork_helper_process(UNIT(s), &pid);
+ if (r < 0)
+ return r;
+ if (r == 0) {
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
- int ret;
+ SocketPort *p;
- (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- (void) ignore_signals(SIGPIPE, -1);
- log_forget_fds();
+ /* Child */
if (!isempty(s->user)) {
const char *user = s->user;
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
- ret = EXIT_USER;
- goto fail_child;
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve user %s: %m", user);
+ _exit(EXIT_USER);
}
}
@@ -1857,8 +1957,8 @@ static int socket_chown(Socket *s, pid_t *_pid) {
r = get_group_creds(&group, &gid);
if (r < 0) {
- ret = EXIT_GROUP;
- goto fail_child;
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve group %s: %m", group);
+ _exit(EXIT_GROUP);
}
}
@@ -1874,19 +1974,12 @@ static int socket_chown(Socket *s, pid_t *_pid) {
continue;
if (chown(path, uid, gid) < 0) {
- r = -errno;
- ret = EXIT_CHOWN;
- goto fail_child;
+ log_unit_error_errno(UNIT(s), errno, "Failed to chown(): %m");
+ _exit(EXIT_CHOWN);
}
}
- _exit(0);
-
- fail_child:
- log_open();
- log_error_errno(r, "Failed to chown socket at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD));
-
- _exit(ret);
+ _exit(EXIT_SUCCESS);
}
r = unit_watch_pid(UNIT(s), pid);
@@ -1907,12 +2000,15 @@ static void socket_enter_dead(Socket *s, SocketResult f) {
if (s->result == SOCKET_SUCCESS)
s->result = f;
+ if (s->result != SOCKET_SUCCESS)
+ log_unit_warning(UNIT(s), "Failed with result '%s'.", socket_result_to_string(s->result));
+
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
exec_runtime_destroy(s->exec_runtime);
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
+ exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
unit_unref_uid_gid(UNIT(s), true);
@@ -1959,7 +2055,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
r = unit_kill_context(
UNIT(s),
&s->kill_context,
- (state != SOCKET_STOP_PRE_SIGTERM && state != SOCKET_FINAL_SIGTERM) ?
+ !IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_FINAL_SIGTERM) ?
KILL_KILL : KILL_TERMINATE,
-1,
s->control_pid,
@@ -1987,7 +2083,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
- if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
+ if (IN_SET(state, SOCKET_STOP_PRE_SIGTERM, SOCKET_STOP_PRE_SIGKILL))
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
else
socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
@@ -2352,15 +2448,13 @@ static int socket_start(Unit *u) {
/* If the service is already active we cannot start the
* socket */
- if (service->state != SERVICE_DEAD &&
- service->state != SERVICE_FAILED &&
- service->state != SERVICE_AUTO_RESTART) {
+ if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
log_unit_error(u, "Socket service %s already active, refusing.", UNIT(service)->id);
return -EBUSY;
}
}
- assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
+ assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
r = unit_start_limit_test(u);
if (r < 0) {
@@ -2373,7 +2467,7 @@ static int socket_start(Unit *u) {
return r;
s->result = SOCKET_SUCCESS;
- s->reset_cpu_usage = true;
+ s->reset_accounting = true;
socket_enter_start_pre(s);
return 1;
@@ -2404,7 +2498,7 @@ static int socket_stop(Unit *u) {
return -EAGAIN;
}
- assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
+ assert(IN_SET(s->state, SOCKET_LISTENING, SOCKET_RUNNING));
socket_enter_stop_pre(s, SOCKET_SUCCESS);
return 1;
@@ -2730,6 +2824,97 @@ _pure_ static bool socket_check_gc(Unit *u) {
return s->n_connections > 0;
}
+static int socket_accept_do(Socket *s, int fd) {
+ int cfd;
+
+ assert(s);
+ assert(fd >= 0);
+
+ for (;;) {
+ cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
+ if (cfd < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+ }
+
+ break;
+ }
+
+ return cfd;
+}
+
+static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ int cfd, r;
+ pid_t pid;
+
+ assert(s);
+ assert(p);
+ assert(fd >= 0);
+
+ /* Similar to socket_address_listen_in_cgroup(), but for accept() rathern than socket(): make sure that any
+ * connection socket is also properly associated with the cgroup. */
+
+ if (!IN_SET(p->address.sockaddr.sa.sa_family, AF_INET, AF_INET6))
+ goto shortcut;
+
+ r = bpf_firewall_supported();
+ if (r < 0)
+ return r;
+ if (r == 0)
+ goto shortcut;
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
+ return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
+
+ r = unit_fork_helper_process(UNIT(s), &pid);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to fork off accept stub process: %m");
+ if (r == 0) {
+ /* Child */
+
+ pair[0] = safe_close(pair[0]);
+
+ cfd = socket_accept_do(s, fd);
+ if (cfd < 0) {
+ log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ r = send_one_fd(pair[1], cfd, 0);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to send connection socket to parent: %m");
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+ cfd = receive_one_fd(pair[0], 0);
+
+ /* We synchronously wait for the helper, as it shouldn't be slow */
+ r = wait_for_terminate_and_warn("accept-cgroup-helper", pid, false);
+ if (r < 0) {
+ safe_close(cfd);
+ return r;
+ }
+
+ if (cfd < 0)
+ return log_unit_error_errno(UNIT(s), cfd, "Failed to receive connection socket: %m");
+
+ return cfd;
+
+shortcut:
+ cfd = socket_accept_do(s, fd);
+ if (cfd < 0)
+ return log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
+
+ return cfd;
+}
+
static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
SocketPort *p = userdata;
int cfd = -1;
@@ -2755,20 +2940,9 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
p->type == SOCKET_SOCKET &&
socket_address_can_accept(&p->address)) {
- for (;;) {
-
- cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
- if (cfd < 0) {
-
- if (errno == EINTR)
- continue;
-
- log_unit_error_errno(UNIT(p->socket), errno, "Failed to accept socket: %m");
- goto fail;
- }
-
- break;
- }
+ cfd = socket_accept_in_cgroup(p->socket, p, fd);
+ if (cfd < 0)
+ goto fail;
socket_apply_socket_options(p->socket, cfd);
}
@@ -2807,7 +2981,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
- if (s->control_command->ignore)
+ if (s->control_command->flags & EXEC_COMMAND_IGNORE_FAILURE)
f = SOCKET_SUCCESS;
}
diff --git a/src/core/socket.h b/src/core/socket.h
index 89f4664510..8c263963c4 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -161,7 +161,7 @@ struct Socket {
char *user, *group;
- bool reset_cpu_usage:1;
+ bool reset_accounting:1;
char *fdname;
diff --git a/src/core/swap.c b/src/core/swap.c
index 4c3a74ce00..f475755572 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -49,8 +49,6 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
[SWAP_ACTIVATING_DONE] = UNIT_ACTIVE,
[SWAP_ACTIVE] = UNIT_ACTIVE,
[SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
- [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
- [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
[SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
[SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
[SWAP_FAILED] = UNIT_FAILED
@@ -59,6 +57,15 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
+ return IN_SET(state,
+ SWAP_ACTIVATING,
+ SWAP_ACTIVATING_DONE,
+ SWAP_DEACTIVATING,
+ SWAP_DEACTIVATING_SIGTERM,
+ SWAP_DEACTIVATING_SIGKILL);
+}
+
static void swap_unset_proc_swaps(Swap *s) {
assert(s);
@@ -487,14 +494,7 @@ static void swap_set_state(Swap *s, SwapState state) {
old_state = s->state;
s->state = state;
- if (!IN_SET(state,
- SWAP_ACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_ACTIVATING_DONE,
- SWAP_DEACTIVATING,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL)) {
+ if (!SWAP_STATE_WITH_PROCESS(state)) {
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
swap_unwatch_control_pid(s);
s->control_command = NULL;
@@ -534,14 +534,7 @@ static int swap_coldplug(Unit *u) {
if (s->control_pid > 0 &&
pid_is_unwaited(s->control_pid) &&
- IN_SET(new_state,
- SWAP_ACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_ACTIVATING_DONE,
- SWAP_DEACTIVATING,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL)) {
+ SWAP_STATE_WITH_PROCESS(new_state)) {
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
@@ -602,13 +595,14 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
+ cgroup_context_dump(&s->cgroup_context, f, prefix);
}
static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -619,9 +613,10 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
assert(_pid);
(void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
+ if (s->reset_accounting) {
+ (void) unit_reset_cpu_accounting(UNIT(s));
+ (void) unit_reset_ip_accounting(UNIT(s));
+ s->reset_accounting = false;
}
r = unit_setup_exec_runtime(UNIT(s));
@@ -630,18 +625,14 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
r = unit_setup_dynamic_creds(UNIT(s));
if (r < 0)
- return r;
+ goto fail;
r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
if (r < 0)
goto fail;
- exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = manager_get_confirm_spawn(UNIT(s)->manager);
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(s)->cgroup_path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
+ manager_set_exec_params(UNIT(s)->manager, &exec_params);
+ unit_set_exec_params(UNIT(s), &exec_params);
r = exec_spawn(UNIT(s),
c,
@@ -664,6 +655,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
fail:
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
+
return r;
}
@@ -673,12 +665,15 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
if (s->result == SWAP_SUCCESS)
s->result = f;
+ if (s->result != SWAP_SUCCESS)
+ log_unit_warning(UNIT(s), "Failed with result '%s'.", swap_result_to_string(s->result));
+
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
exec_runtime_destroy(s->exec_runtime);
s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
+ exec_context_destroy_runtime_directory(&s->exec_context, UNIT(s)->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
unit_unref_uid_gid(UNIT(s), true);
@@ -694,6 +689,15 @@ static void swap_enter_active(Swap *s, SwapResult f) {
swap_set_state(s, SWAP_ACTIVE);
}
+static void swap_enter_dead_or_active(Swap *s, SwapResult f) {
+ assert(s);
+
+ if (s->from_proc_swaps)
+ swap_enter_active(s, f);
+ else
+ swap_enter_dead(s, f);
+}
+
static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
int r;
KillOperation kop;
@@ -703,7 +707,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
if (s->result == SWAP_SUCCESS)
s->result = f;
- if (IN_SET(state, SWAP_ACTIVATING_SIGTERM, SWAP_DEACTIVATING_SIGTERM))
+ if (state == SWAP_DEACTIVATING_SIGTERM)
kop = KILL_TERMINATE;
else
kop = KILL_KILL;
@@ -718,18 +722,16 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
goto fail;
swap_set_state(s, state);
- } else if (state == SWAP_ACTIVATING_SIGTERM)
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS);
- else if (state == SWAP_DEACTIVATING_SIGTERM)
+ } else if (state == SWAP_DEACTIVATING_SIGTERM && s->kill_context.send_sigkill)
swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
else
- swap_enter_dead(s, SWAP_SUCCESS);
+ swap_enter_dead_or_active(s, SWAP_SUCCESS);
return;
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
+ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
}
static void swap_enter_activating(Swap *s) {
@@ -787,7 +789,7 @@ static void swap_enter_activating(Swap *s) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapon' task: %m");
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
+ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
}
static void swap_enter_deactivating(Swap *s) {
@@ -817,7 +819,7 @@ static void swap_enter_deactivating(Swap *s) {
fail:
log_unit_warning_errno(UNIT(s), r, "Failed to run 'swapoff' task: %m");
- swap_enter_active(s, SWAP_FAILURE_RESOURCES);
+ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES);
}
static int swap_start(Unit *u) {
@@ -826,17 +828,14 @@ static int swap_start(Unit *u) {
assert(s);
- /* We cannot fulfill this request right now, try again later
- * please! */
-
+ /* We cannot fulfill this request right now, try again later please! */
if (IN_SET(s->state,
SWAP_DEACTIVATING,
SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL))
+ SWAP_DEACTIVATING_SIGKILL))
return -EAGAIN;
+ /* Already on it! */
if (s->state == SWAP_ACTIVATING)
return 0;
@@ -863,7 +862,7 @@ static int swap_start(Unit *u) {
return r;
s->result = SWAP_SUCCESS;
- s->reset_cpu_usage = true;
+ s->reset_accounting = true;
swap_enter_activating(s);
return 1;
@@ -874,21 +873,30 @@ static int swap_stop(Unit *u) {
assert(s);
- if (IN_SET(s->state,
- SWAP_DEACTIVATING,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL))
+ switch (s->state) {
+
+ case SWAP_DEACTIVATING:
+ case SWAP_DEACTIVATING_SIGTERM:
+ case SWAP_DEACTIVATING_SIGKILL:
+ /* Already on it */
return 0;
- assert(IN_SET(s->state, SWAP_ACTIVATING, SWAP_ACTIVATING_DONE, SWAP_ACTIVE));
+ case SWAP_ACTIVATING:
+ case SWAP_ACTIVATING_DONE:
+ /* There's a control process pending, directly enter kill mode */
+ swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_SUCCESS);
+ return 0;
- if (detect_container() > 0)
- return -EPERM;
+ case SWAP_ACTIVE:
+ if (detect_container() > 0)
+ return -EPERM;
- swap_enter_deactivating(s);
- return 1;
+ swap_enter_deactivating(s);
+ return 1;
+
+ default:
+ assert_not_reached("Unexpected state.");
+ }
}
static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
@@ -1016,10 +1024,8 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SWAP_ACTIVATING:
case SWAP_ACTIVATING_DONE:
- case SWAP_ACTIVATING_SIGTERM:
- case SWAP_ACTIVATING_SIGKILL:
- if (f == SWAP_SUCCESS)
+ if (f == SWAP_SUCCESS || s->from_proc_swaps)
swap_enter_active(s, f);
else
swap_enter_dead(s, f);
@@ -1029,7 +1035,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
case SWAP_DEACTIVATING_SIGKILL:
case SWAP_DEACTIVATING_SIGTERM:
- swap_enter_dead(s, f);
+ swap_enter_dead_or_active(s, f);
break;
default:
@@ -1051,7 +1057,7 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
case SWAP_ACTIVATING:
case SWAP_ACTIVATING_DONE:
log_unit_warning(UNIT(s), "Activation timed out. Stopping.");
- swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
+ swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
case SWAP_DEACTIVATING:
@@ -1059,30 +1065,19 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
- case SWAP_ACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s), "Activation timed out. Killing.");
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Activation timed out. Skipping SIGKILL. Ignoring.");
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
case SWAP_DEACTIVATING_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s), "Deactivation timed out. Killing.");
+ log_unit_warning(UNIT(s), "Swap process timed out. Killing.");
swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
} else {
- log_unit_warning(UNIT(s), "Deactivation timed out. Skipping SIGKILL. Ignoring.");
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
+ log_unit_warning(UNIT(s), "Swap process timed out. Skipping SIGKILL. Ignoring.");
+ swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT);
}
break;
- case SWAP_ACTIVATING_SIGKILL:
case SWAP_DEACTIVATING_SIGKILL:
log_unit_warning(UNIT(s), "Swap process still around after SIGKILL. Ignoring.");
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
+ swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT);
break;
default:
diff --git a/src/core/swap.h b/src/core/swap.h
index b0ef50f1e8..45da63c5e2 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -70,7 +70,7 @@ struct Swap {
bool is_active:1;
bool just_activated:1;
- bool reset_cpu_usage:1;
+ bool reset_accounting:1;
SwapResult result;
diff --git a/src/core/system.conf b/src/core/system.conf
index 746572b7ff..6b86eac33d 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -40,6 +40,7 @@
#DefaultEnvironment=
#DefaultCPUAccounting=no
#DefaultIOAccounting=no
+#DefaultIPAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
#DefaultTasksAccounting=yes
@@ -60,3 +61,5 @@
#DefaultLimitNICE=
#DefaultLimitRTPRIO=
#DefaultLimitRTTIME=
+#IPAddressAllow=
+#IPAddressDeny=
diff --git a/src/core/timer.c b/src/core/timer.c
index 2b2370d536..8b3d54bb67 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -296,6 +296,9 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
if (t->result == TIMER_SUCCESS)
t->result = f;
+ if (t->result != TIMER_SUCCESS)
+ log_unit_warning(UNIT(t), "Failed with result '%s'.", timer_result_to_string(t->result));
+
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
}
@@ -587,7 +590,7 @@ static int timer_start(Unit *u) {
int r;
assert(t);
- assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
+ assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
trigger = UNIT_TRIGGER(u);
if (!trigger || trigger->load_state != UNIT_LOADED) {
@@ -615,9 +618,23 @@ static int timer_start(Unit *u) {
if (t->stamp_path) {
struct stat st;
- if (stat(t->stamp_path, &st) >= 0)
- t->last_trigger.realtime = timespec_load(&st.st_atim);
- else if (errno == ENOENT)
+ if (stat(t->stamp_path, &st) >= 0) {
+ usec_t ft;
+
+ /* Load the file timestamp, but only if it is actually in the past. If it is in the future,
+ * something is wrong with the system clock. */
+
+ ft = timespec_load(&st.st_mtim);
+ if (ft < now(CLOCK_REALTIME))
+ t->last_trigger.realtime = ft;
+ else {
+ char z[FORMAT_TIMESTAMP_MAX];
+
+ log_unit_warning(u, "Not using persistent file timestamp %s as it is in the future.",
+ format_timestamp(z, sizeof(z), ft));
+ }
+
+ } else if (errno == ENOENT)
/* The timer has never run before,
* make sure a stamp file exists.
*/
@@ -633,7 +650,7 @@ static int timer_stop(Unit *u) {
Timer *t = TIMER(u);
assert(t);
- assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
+ assert(IN_SET(t->state, TIMER_WAITING, TIMER_RUNNING, TIMER_ELAPSED));
timer_enter_dead(t, TIMER_SUCCESS);
return 1;
@@ -738,8 +755,7 @@ static void timer_trigger_notify(Unit *u, Unit *other) {
/* Reenable all timers that depend on unit state */
LIST_FOREACH(value, v, t->values)
- if (v->base == TIMER_UNIT_ACTIVE ||
- v->base == TIMER_UNIT_INACTIVE)
+ if (IN_SET(v->base, TIMER_UNIT_ACTIVE, TIMER_UNIT_INACTIVE))
v->disabled = false;
switch (t->state) {
diff --git a/src/core/transaction.c b/src/core/transaction.c
index a2dfd8ae90..46c2fa452e 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -338,6 +338,26 @@ _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
return false;
}
+static char* merge_unit_ids(const char* unit_log_field, char **pairs) {
+ char **unit_id, **job_type, *ans = NULL;
+ size_t alloc = 0, size = 0, next;
+
+ STRV_FOREACH_PAIR(unit_id, job_type, pairs) {
+ next = strlen(unit_log_field) + strlen(*unit_id);
+ if (!GREEDY_REALLOC(ans, alloc, size + next + 1)) {
+ free(ans);
+ return NULL;
+ }
+
+ sprintf(ans + size, "%s%s", unit_log_field, *unit_id);
+ if (*(unit_id+1))
+ ans[size + next] = '\n';
+ size += next + 1;
+ }
+
+ return ans;
+}
+
static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
Iterator i;
Unit *u;
@@ -352,7 +372,9 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
/* Have we seen this before? */
if (j->generation == generation) {
- Job *k, *delete;
+ Job *k, *delete = NULL;
+ _cleanup_free_ char **array = NULL, *unit_ids = NULL;
+ char **unit_id, **job_type;
/* If the marker is NULL we have been here already and
* decided the job was loop-free from here. Hence
@@ -360,46 +382,46 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
if (!j->marker)
return 0;
- /* So, the marker is not NULL and we already have been
- * here. We have a cycle. Let's try to break it. We go
- * backwards in our path and try to find a suitable
- * job to remove. We use the marker to find our way
- * back, since smart how we are we stored our way back
- * in there. */
- log_unit_warning(j->unit,
- "Found ordering cycle on %s/%s",
- j->unit->id, job_type_to_string(j->type));
-
- delete = NULL;
+ /* So, the marker is not NULL and we already have been here. We have
+ * a cycle. Let's try to break it. We go backwards in our path and
+ * try to find a suitable job to remove. We use the marker to find
+ * our way back, since smart how we are we stored our way back in
+ * there. */
+
for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
- /* logging for j not k here to provide consistent narrative */
- log_unit_warning(j->unit,
- "Found dependency on %s/%s",
- k->unit->id, job_type_to_string(k->type));
+ /* For logging below */
+ if (strv_push_pair(&array, k->unit->id, (char*) job_type_to_string(k->type)) < 0)
+ log_oom();
if (!delete && hashmap_get(tr->jobs, k->unit) && !unit_matters_to_anchor(k->unit, k))
- /* Ok, we can drop this one, so let's
- * do so. */
+ /* Ok, we can drop this one, so let's do so. */
delete = k;
- /* Check if this in fact was the beginning of
- * the cycle */
+ /* Check if this in fact was the beginning of the cycle */
if (k == j)
break;
}
+ unit_ids = merge_unit_ids(j->manager->unit_log_field, array); /* ignore error */
+
+ STRV_FOREACH_PAIR(unit_id, job_type, array)
+ /* logging for j not k here to provide a consistent narrative */
+ log_struct(LOG_WARNING,
+ "MESSAGE=%s: Found %s on %s/%s",
+ j->unit->id,
+ unit_id == array ? "ordering cycle" : "dependency",
+ *unit_id, *job_type,
+ unit_ids, NULL);
if (delete) {
const char *status;
- /* logging for j not k here to provide consistent narrative */
- log_unit_warning(j->unit,
- "Breaking ordering cycle by deleting job %s/%s",
- delete->unit->id, job_type_to_string(delete->type));
- log_unit_error(delete->unit,
- "Job %s/%s deleted to break ordering cycle starting with %s/%s",
- delete->unit->id, job_type_to_string(delete->type),
- j->unit->id, job_type_to_string(j->type));
+ /* logging for j not k here to provide a consistent narrative */
+ log_struct(LOG_ERR,
+ "MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s",
+ j->unit->id, delete->unit->id, job_type_to_string(delete->type),
+ j->unit->id, job_type_to_string(j->type),
+ unit_ids, NULL);
if (log_get_show_color())
status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL;
@@ -412,7 +434,10 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
return -EAGAIN;
}
- log_error("Unable to break cycle");
+ log_struct(LOG_ERR,
+ "MESSAGE=%s: Unable to break cycle starting with %s/%s",
+ j->unit->id, j->unit->id, job_type_to_string(j->type),
+ unit_ids, NULL);
return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
"Transaction order is cyclic. See system logs for details.");
@@ -584,7 +609,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
/* Moves the transaction jobs to the set of active jobs */
- if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
+ if (IN_SET(mode, JOB_ISOLATE, JOB_FLUSH)) {
/* When isolating first kill all installed jobs which
* aren't part of the new transaction */
@@ -833,6 +858,30 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen
}
}
+void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e) {
+ Iterator i;
+ Unit *dep;
+ JobType nt;
+ int r;
+
+ assert(tr);
+ assert(unit);
+
+ SET_FOREACH(dep, unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
+ nt = job_type_collapse(JOB_TRY_RELOAD, dep);
+ if (nt == JOB_NOP)
+ continue;
+
+ r = transaction_add_job_and_dependencies(tr, nt, dep, by, false, false, false, ignore_order, e);
+ if (r < 0) {
+ log_unit_warning(dep,
+ "Cannot add dependency reload job, ignoring: %s",
+ bus_error_message(e, r));
+ sd_bus_error_free(e);
+ }
+ }
+}
+
int transaction_add_job_and_dependencies(
Transaction *tr,
JobType type,
@@ -919,7 +968,7 @@ int transaction_add_job_and_dependencies(
}
/* Finally, recursively add in all dependencies. */
- if (type == JOB_START || type == JOB_RESTART) {
+ if (IN_SET(type, JOB_START, JOB_RESTART)) {
SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
@@ -984,7 +1033,7 @@ int transaction_add_job_and_dependencies(
}
- if (type == JOB_STOP || type == JOB_RESTART) {
+ if (IN_SET(type, JOB_STOP, JOB_RESTART)) {
static const UnitDependency propagate_deps[] = {
UNIT_REQUIRED_BY,
UNIT_REQUISITE_OF,
@@ -1018,24 +1067,8 @@ int transaction_add_job_and_dependencies(
}
}
- if (type == JOB_RELOAD) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
- JobType nt;
-
- nt = job_type_collapse(JOB_TRY_RELOAD, dep);
- if (nt == JOB_NOP)
- continue;
-
- r = transaction_add_job_and_dependencies(tr, nt, dep, ret, false, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep,
- "Cannot add dependency reload job, ignoring: %s",
- bus_error_message(e, r));
- sd_bus_error_free(e);
- }
- }
- }
+ if (type == JOB_RELOAD)
+ transaction_add_propagate_reload_jobs(tr, ret->unit, ret, ignore_order, e);
/* JOB_VERIFY_STARTED require no dependency handling */
}
diff --git a/src/core/transaction.h b/src/core/transaction.h
index 6a3f927b0f..ddfdbf9987 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -36,6 +36,7 @@ struct Transaction {
Transaction *transaction_new(bool irreversible);
void transaction_free(Transaction *tr);
+void transaction_add_propagate_reload_jobs(Transaction *tr, Unit *unit, Job *by, bool ignore_order, sd_bus_error *e);
int transaction_add_job_and_dependencies(
Transaction *tr,
JobType type,
diff --git a/src/core/umount.c b/src/core/umount.c
index 591dac71f0..813d257139 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -37,12 +37,14 @@
#include "string-util.h"
#include "udev-util.h"
#include "umount.h"
+#include "mount-util.h"
#include "util.h"
#include "virt.h"
typedef struct MountPoint {
char *path;
char *options;
+ char *type;
dev_t devnum;
LIST_FIELDS(struct MountPoint, mount_point);
} MountPoint;
@@ -76,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) {
return -errno;
for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL, *options = NULL;
+ _cleanup_free_ char *path = NULL, *options = NULL, *type = NULL;
char *p = NULL;
MountPoint *m;
int k;
@@ -90,12 +92,12 @@ static int mount_points_list_get(MountPoint **head) {
"%*s" /* (6) mount flags */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
- "%*s " /* (9) file system type */
+ "%ms " /* (9) file system type */
"%*s" /* (10) mount source */
"%ms" /* (11) mount options */
"%*[^\n]", /* some rubbish at the end */
- &path, &options);
- if (k != 2) {
+ &path, &type, &options);
+ if (k != 3) {
if (k == EOF)
break;
@@ -132,6 +134,8 @@ static int mount_points_list_get(MountPoint **head) {
m->path = p;
m->options = options;
options = NULL;
+ m->type = type;
+ type = NULL;
LIST_PREPEND(mount_point, *head, m);
}
@@ -371,7 +375,7 @@ static int delete_dm(dev_t devnum) {
static bool nonunmountable_path(const char *path) {
return path_equal(path, "/")
-#ifndef HAVE_SPLIT_USR
+#if ! HAVE_SPLIT_USR
|| path_equal(path, "/usr")
#endif
|| path_startswith(path, "/run/initramfs");
@@ -388,8 +392,12 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
/* If we are in a container, don't attempt to
read-only mount anything as that brings no real
benefits, but might confuse the host, as we remount
- the superblock here, not the bind mount. */
- if (detect_container() <= 0) {
+ the superblock here, not the bind mount.
+ If the filesystem is a network fs, also skip the
+ remount. It brings no value (we cannot leave
+ a "dirty fs") and could hang if the network is down. */
+ if (detect_container() <= 0 &&
+ !fstype_is_network(m->type)) {
_cleanup_free_ char *options = NULL;
/* MS_REMOUNT requires that the data parameter
* should be the same from the original mount
@@ -509,22 +517,22 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
static int dm_points_list_detach(MountPoint **head, bool *changed) {
MountPoint *m, *n;
- int n_failed = 0, k;
- struct stat root_st;
+ int n_failed = 0, r;
+ dev_t rootdev;
assert(head);
- k = lstat("/", &root_st);
+ r = get_block_device("/", &rootdev);
+ if (r <= 0)
+ rootdev = 0;
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- int r;
- if (k >= 0 &&
- major(root_st.st_dev) != 0 &&
- root_st.st_dev == m->devnum) {
- n_failed++;
- continue;
- }
+ if (major(rootdev) != 0)
+ if (rootdev == m->devnum) {
+ n_failed ++;
+ continue;
+ }
log_info("Detaching DM %u:%u.", major(m->devnum), minor(m->devnum));
r = delete_dm(m->devnum);
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index 746e1a46ef..0480ec6526 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -145,15 +145,11 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
- const char *e;
char *n = NULL;
assert(u);
- e = manager_get_runtime_prefix(u->manager);
- if (!e)
- return -EOPNOTSUPP;
- n = strdup(e);
+ n = strdup(u->manager->prefix[EXEC_DIRECTORY_RUNTIME]);
if (!n)
return -ENOMEM;
diff --git a/src/core/unit.c b/src/core/unit.c
index b28eeb2262..357306dce8 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -35,9 +35,11 @@
#include "dropin.h"
#include "escape.h"
#include "execute.h"
+#include "fd-util.h"
#include "fileio-label.h"
#include "format-util.h"
#include "id128-util.h"
+#include "io-util.h"
#include "load-dropin.h"
#include "load-fragment.h"
#include "log.h"
@@ -63,7 +65,6 @@
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
[UNIT_SOCKET] = &socket_vtable,
- [UNIT_BUSNAME] = &busname_vtable,
[UNIT_TARGET] = &target_vtable,
[UNIT_DEVICE] = &device_vtable,
[UNIT_MOUNT] = &mount_vtable,
@@ -104,6 +105,13 @@ Unit *unit_new(Manager *m, size_t size) {
u->ref_gid = GID_INVALID;
u->cpu_usage_last = NSEC_INFINITY;
+ u->ip_accounting_ingress_map_fd = -1;
+ u->ip_accounting_egress_map_fd = -1;
+ u->ipv4_allow_map_fd = -1;
+ u->ipv6_allow_map_fd = -1;
+ u->ipv4_deny_map_fd = -1;
+ u->ipv6_deny_map_fd = -1;
+
RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
@@ -154,18 +162,24 @@ static void unit_init(Unit *u) {
cc->cpu_accounting = u->manager->default_cpu_accounting;
cc->io_accounting = u->manager->default_io_accounting;
+ cc->ip_accounting = u->manager->default_ip_accounting;
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
+ cc->ip_accounting = u->manager->default_ip_accounting;
if (u->type != UNIT_SLICE)
cc->tasks_max = u->manager->default_tasks_max;
}
ec = unit_get_exec_context(u);
- if (ec)
+ if (ec) {
exec_context_init(ec);
+ ec->keyring_mode = MANAGER_IS_SYSTEM(u->manager) ?
+ EXEC_KEYRING_PRIVATE : EXEC_KEYRING_INHERIT;
+ }
+
kc = unit_get_kill_context(u);
if (kc)
kill_context_init(kc);
@@ -300,22 +314,16 @@ int unit_choose_id(Unit *u, const char *name) {
}
int unit_set_description(Unit *u, const char *description) {
- char *s;
+ int r;
assert(u);
- if (isempty(description))
- s = NULL;
- else {
- s = strdup(description);
- if (!s)
- return -ENOMEM;
- }
-
- free(u->description);
- u->description = s;
+ r = free_and_strdup(&u->description, empty_to_null(description));
+ if (r < 0)
+ return r;
+ if (r > 0)
+ unit_add_to_dbus_queue(u);
- unit_add_to_dbus_queue(u);
return 0;
}
@@ -574,8 +582,11 @@ void unit_free(Unit *u) {
if (u->in_gc_queue)
LIST_REMOVE(gc_queue, u->manager->gc_unit_queue, u);
- if (u->in_cgroup_queue)
- LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
+ if (u->in_cgroup_realize_queue)
+ LIST_REMOVE(cgroup_realize_queue, u->manager->cgroup_realize_queue, u);
+
+ if (u->in_cgroup_empty_queue)
+ LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u);
unit_release_cgroup(u);
@@ -607,6 +618,17 @@ void unit_free(Unit *u) {
while (u->refs)
unit_ref_unset(u->refs);
+ safe_close(u->ip_accounting_ingress_map_fd);
+ safe_close(u->ip_accounting_egress_map_fd);
+
+ safe_close(u->ipv4_allow_map_fd);
+ safe_close(u->ipv6_allow_map_fd);
+ safe_close(u->ipv4_deny_map_fd);
+ safe_close(u->ipv6_deny_map_fd);
+
+ bpf_program_unref(u->ip_bpf_ingress);
+ bpf_program_unref(u->ip_bpf_egress);
+
free(u);
}
@@ -756,8 +778,7 @@ int unit_merge(Unit *u, Unit *other) {
if (!unit_type_may_alias(u->type)) /* Merging only applies to unit names that support aliases */
return -EEXIST;
- if (other->load_state != UNIT_STUB &&
- other->load_state != UNIT_NOT_FOUND)
+ if (!IN_SET(other->load_state, UNIT_STUB, UNIT_NOT_FOUND))
return -EEXIST;
if (other->job)
@@ -847,6 +868,8 @@ Unit* unit_follow_merge(Unit *u) {
}
int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
+ ExecDirectoryType dt;
+ char **dp;
int r;
assert(u);
@@ -870,6 +893,23 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
return r;
}
+ for (dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
+ if (!u->manager->prefix[dt])
+ continue;
+
+ STRV_FOREACH(dp, c->directories[dt].paths) {
+ _cleanup_free_ char *p;
+
+ p = strjoin(u->manager->prefix[dt], "/", *dp);
+ if (!p)
+ return -ENOMEM;
+
+ r = unit_require_mounts_for(u, p);
+ if (r < 0)
+ return r;
+ }
+ }
+
if (!MANAGER_IS_SYSTEM(u->manager))
return 0;
@@ -1098,7 +1138,6 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
/* Common implementation for multiple backends */
int unit_load_fragment_and_dropin(Unit *u) {
- Unit *t;
int r;
assert(u);
@@ -1111,18 +1150,15 @@ int unit_load_fragment_and_dropin(Unit *u) {
if (u->load_state == UNIT_STUB)
return -ENOENT;
- /* If the unit is an alias and the final unit has already been
- * loaded, there's no point in reloading the dropins one more time. */
- t = unit_follow_merge(u);
- if (t != u && t->load_state != UNIT_STUB)
- return 0;
-
- return unit_load_dropin(t);
+ /* Load drop-in directory data. If u is an alias, we might be reloading the
+ * target unit needlessly. But we cannot be sure which drops-ins have already
+ * been loaded and which not, at least without doing complicated book-keeping,
+ * so let's always reread all drop-ins. */
+ return unit_load_dropin(unit_follow_merge(u));
}
/* Common implementation for multiple backends */
int unit_load_fragment_and_dropin_optional(Unit *u) {
- Unit *t;
int r;
assert(u);
@@ -1138,13 +1174,8 @@ int unit_load_fragment_and_dropin_optional(Unit *u) {
if (u->load_state == UNIT_STUB)
u->load_state = UNIT_LOADED;
- /* If the unit is an alias and the final unit has already been
- * loaded, there's no point in reloading the dropins one more time. */
- t = unit_follow_merge(u);
- if (t != u && t->load_state != UNIT_STUB)
- return 0;
-
- return unit_load_dropin(t);
+ /* Load drop-in directory data */
+ return unit_load_dropin(unit_follow_merge(u));
}
int unit_add_default_target_dependency(Unit *u, Unit *target) {
@@ -1510,6 +1541,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
log_struct(LOG_INFO,
LOG_MESSAGE("%s", buf),
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
mid,
NULL);
}
@@ -1750,19 +1782,25 @@ int unit_reload(Unit *u) {
unit_add_to_dbus_queue(u);
+ if (!UNIT_VTABLE(u)->reload) {
+ /* Unit doesn't have a reload function, but we need to propagate the reload anyway */
+ unit_notify(u, unit_active_state(u), unit_active_state(u), true);
+ return 0;
+ }
+
return UNIT_VTABLE(u)->reload(u);
}
bool unit_can_reload(Unit *u) {
assert(u);
- if (!UNIT_VTABLE(u)->reload)
- return false;
+ if (UNIT_VTABLE(u)->can_reload)
+ return UNIT_VTABLE(u)->can_reload(u);
- if (!UNIT_VTABLE(u)->can_reload)
+ if (!set_isempty(u->dependencies[UNIT_PROPAGATES_RELOAD_TO]))
return true;
- return UNIT_VTABLE(u)->can_reload(u);
+ return UNIT_VTABLE(u)->reload;
}
static void unit_check_unneeded(Unit *u) {
@@ -1960,6 +1998,134 @@ void unit_trigger_notify(Unit *u) {
UNIT_VTABLE(other)->trigger_notify(other, u);
}
+static int unit_log_resources(Unit *u) {
+
+ struct iovec iovec[1 + _CGROUP_IP_ACCOUNTING_METRIC_MAX + 4];
+ size_t n_message_parts = 0, n_iovec = 0;
+ char* message_parts[3 + 1], *t;
+ nsec_t nsec = NSEC_INFINITY;
+ CGroupIPAccountingMetric m;
+ size_t i;
+ int r;
+ const char* const ip_fields[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
+ [CGROUP_IP_INGRESS_BYTES] = "IP_METRIC_INGRESS_BYTES",
+ [CGROUP_IP_INGRESS_PACKETS] = "IP_METRIC_INGRESS_PACKETS",
+ [CGROUP_IP_EGRESS_BYTES] = "IP_METRIC_EGRESS_BYTES",
+ [CGROUP_IP_EGRESS_PACKETS] = "IP_METRIC_EGRESS_PACKETS",
+ };
+
+ assert(u);
+
+ /* Invoked whenever a unit enters failed or dead state. Logs information about consumed resources if resource
+ * accounting was enabled for a unit. It does this in two ways: a friendly human readable string with reduced
+ * information and the complete data in structured fields. */
+
+ (void) unit_get_cpu_usage(u, &nsec);
+ if (nsec != NSEC_INFINITY) {
+ char buf[FORMAT_TIMESPAN_MAX] = "";
+
+ /* Format the CPU time for inclusion in the structured log message */
+ if (asprintf(&t, "CPU_USAGE_NSEC=%" PRIu64, nsec) < 0) {
+ r = log_oom();
+ goto finish;
+ }
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(t);
+
+ /* Format the CPU time for inclusion in the human language message string */
+ format_timespan(buf, sizeof(buf), nsec / NSEC_PER_USEC, USEC_PER_MSEC);
+ t = strjoin(n_message_parts > 0 ? "consumed " : "Consumed ", buf, " CPU time");
+ if (!t) {
+ r = log_oom();
+ goto finish;
+ }
+
+ message_parts[n_message_parts++] = t;
+ }
+
+ for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
+ char buf[FORMAT_BYTES_MAX] = "";
+ uint64_t value = UINT64_MAX;
+
+ assert(ip_fields[m]);
+
+ (void) unit_get_ip_accounting(u, m, &value);
+ if (value == UINT64_MAX)
+ continue;
+
+ /* Format IP accounting data for inclusion in the structured log message */
+ if (asprintf(&t, "%s=%" PRIu64, ip_fields[m], value) < 0) {
+ r = log_oom();
+ goto finish;
+ }
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(t);
+
+ /* Format the IP accounting data for inclusion in the human language message string, but only for the
+ * bytes counters (and not for the packets counters) */
+ if (m == CGROUP_IP_INGRESS_BYTES)
+ t = strjoin(n_message_parts > 0 ? "received " : "Received ",
+ format_bytes(buf, sizeof(buf), value),
+ " IP traffic");
+ else if (m == CGROUP_IP_EGRESS_BYTES)
+ t = strjoin(n_message_parts > 0 ? "sent " : "Sent ",
+ format_bytes(buf, sizeof(buf), value),
+ " IP traffic");
+ else
+ continue;
+ if (!t) {
+ r = log_oom();
+ goto finish;
+ }
+
+ message_parts[n_message_parts++] = t;
+ }
+
+ /* Is there any accounting data available at all? */
+ if (n_iovec == 0) {
+ r = 0;
+ goto finish;
+ }
+
+ if (n_message_parts == 0)
+ t = strjoina("MESSAGE=", u->id, ": Completed");
+ else {
+ _cleanup_free_ char *joined;
+
+ message_parts[n_message_parts] = NULL;
+
+ joined = strv_join(message_parts, ", ");
+ if (!joined) {
+ r = log_oom();
+ goto finish;
+ }
+
+ t = strjoina("MESSAGE=", u->id, ": ", joined);
+ }
+
+ /* The following four fields we allocate on the stack or are static strings, we hence don't want to free them,
+ * and hence don't increase n_iovec for them */
+ iovec[n_iovec] = IOVEC_MAKE_STRING(t);
+ iovec[n_iovec + 1] = IOVEC_MAKE_STRING("MESSAGE_ID=" SD_MESSAGE_UNIT_RESOURCES_STR);
+
+ t = strjoina(u->manager->unit_log_field, u->id);
+ iovec[n_iovec + 2] = IOVEC_MAKE_STRING(t);
+
+ t = strjoina(u->manager->invocation_log_field, u->invocation_id_string);
+ iovec[n_iovec + 3] = IOVEC_MAKE_STRING(t);
+
+ log_struct_iovec(LOG_INFO, iovec, n_iovec + 4);
+ r = 0;
+
+finish:
+ for (i = 0; i < n_message_parts; i++)
+ free(message_parts[i]);
+
+ for (i = 0; i < n_iovec; i++)
+ free(iovec[i].iov_base);
+
+ return r;
+
+}
+
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
Manager *m;
bool unexpected;
@@ -2054,7 +2220,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false);
- else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
+ else if (!IN_SET(ns, UNIT_ACTIVATING, UNIT_RELOADING)) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -2105,7 +2271,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
check_unneeded_dependencies(u);
if (ns != os && ns == UNIT_FAILED) {
- log_unit_notice(u, "Unit entered failed state.");
+ log_unit_debug(u, "Unit entered failed state.");
unit_start_on_failure(u);
}
}
@@ -2131,28 +2297,33 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
manager_send_unit_plymouth(m, u);
} else {
+ /* We don't care about D-Bus going down here, since we'll get an asynchronous notification for it
+ * anyway. */
- /* We don't care about D-Bus here, since we'll get an
- * asynchronous notification for it anyway. */
+ if (UNIT_IS_INACTIVE_OR_FAILED(ns) &&
+ !UNIT_IS_INACTIVE_OR_FAILED(os)
+ && !MANAGER_IS_RELOADING(m)) {
- if (u->type == UNIT_SERVICE &&
- UNIT_IS_INACTIVE_OR_FAILED(ns) &&
- !UNIT_IS_INACTIVE_OR_FAILED(os) &&
- !MANAGER_IS_RELOADING(m)) {
+ /* This unit just stopped/failed. */
+ if (u->type == UNIT_SERVICE) {
- /* Hmm, if there was no start record written
- * write it now, so that we always have a nice
- * pair */
- if (!u->in_audit) {
- manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
+ /* Hmm, if there was no start record written
+ * write it now, so that we always have a nice
+ * pair */
+ if (!u->in_audit) {
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
- if (ns == UNIT_INACTIVE)
- manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
- } else
- /* Write audit record if we have just finished shutting down */
- manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
+ if (ns == UNIT_INACTIVE)
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
+ } else
+ /* Write audit record if we have just finished shutting down */
+ manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
- u->in_audit = false;
+ u->in_audit = false;
+ }
+
+ /* Write a log message about consumed resources */
+ unit_log_resources(u);
}
}
@@ -2730,7 +2901,15 @@ static int unit_serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask)
return r;
}
+static const char *ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
+ [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
+ [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
+ [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
+ [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
+};
+
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
+ CGroupIPAccountingMetric m;
int r;
assert(u);
@@ -2779,6 +2958,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized));
(void) unit_serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask);
(void) unit_serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask);
+ unit_serialize_item_format(u, f, "cgroup-bpf-realized", "%i", u->cgroup_bpf_state);
if (uid_is_valid(u->ref_uid))
unit_serialize_item_format(u, f, "ref-uid", UID_FMT, u->ref_uid);
@@ -2790,6 +2970,14 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
bus_track_serialize(u->bus_track, f, "ref");
+ for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
+ uint64_t v;
+
+ r = unit_get_ip_accounting(u, m, &v);
+ if (r >= 0)
+ unit_serialize_item_format(u, f, ip_accounting_metric_field[m], "%" PRIu64, v);
+ }
+
if (serialize_jobs) {
if (u->job) {
fprintf(f, "job\n");
@@ -2896,6 +3084,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
for (;;) {
char line[LINE_MAX], *l, *v;
+ CGroupIPAccountingMetric m;
size_t k;
if (!fgets(line, sizeof(line), f)) {
@@ -3050,6 +3239,20 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v);
continue;
+ } else if (streq(l, "cgroup-bpf-realized")) {
+ int i;
+
+ r = safe_atoi(v, &i);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse cgroup BPF state %s, ignoring.", v);
+ else
+ u->cgroup_bpf_state =
+ i < 0 ? UNIT_CGROUP_BPF_INVALIDATED :
+ i > 0 ? UNIT_CGROUP_BPF_ON :
+ UNIT_CGROUP_BPF_OFF;
+
+ continue;
+
} else if (streq(l, "ref-uid")) {
uid_t uid;
@@ -3092,6 +3295,21 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
}
+ /* Check if this is an IP accounting metric serialization field */
+ for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++)
+ if (streq(l, ip_accounting_metric_field[m]))
+ break;
+ if (m < _CGROUP_IP_ACCOUNTING_METRIC_MAX) {
+ uint64_t c;
+
+ r = safe_atou64(v, &c);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v);
+ else
+ u->ip_accounting_extra[m] = c;
+ continue;
+ }
+
if (unit_can_serialize(u)) {
if (rt) {
r = exec_runtime_deserialize_item(u, rt, l, v, fds);
@@ -3118,9 +3336,35 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
if (!dual_timestamp_is_set(&u->state_change_timestamp))
dual_timestamp_get(&u->state_change_timestamp);
+ /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings applied
+ * after we are done. For that we invalidate anything already realized, so that we can realize it again. */
+ unit_invalidate_cgroup(u, _CGROUP_MASK_ALL);
+ unit_invalidate_cgroup_bpf(u);
+
return 0;
}
+void unit_deserialize_skip(FILE *f) {
+ assert(f);
+
+ /* Skip serialized data for this unit. We don't know what it is. */
+
+ for (;;) {
+ char line[LINE_MAX], *l;
+
+ if (!fgets(line, sizeof line, f))
+ return;
+
+ char_array_0(line);
+ l = strstrip(line);
+
+ /* End marker */
+ if (isempty(l))
+ return;
+ }
+}
+
+
int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
Unit *device;
_cleanup_free_ char *e = NULL;
@@ -3307,9 +3551,7 @@ bool unit_active_or_pending(Unit *u) {
return true;
if (u->job &&
- (u->job->type == JOB_START ||
- u->job->type == JOB_RELOAD_OR_START ||
- u->job->type == JOB_RESTART))
+ IN_SET(u->job->type, JOB_START, JOB_RELOAD_OR_START, JOB_RESTART))
return true;
return false;
@@ -3405,7 +3647,7 @@ int unit_kill_common(
return -ENOMEM;
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, NULL, NULL);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
+ if (q < 0 && !IN_SET(q, -EAGAIN, -ESRCH, -ENOENT))
r = q;
else
killed = true;
@@ -3937,7 +4179,7 @@ int unit_kill_context(
pid_set,
log_func, u);
if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+ if (!IN_SET(r, -EAGAIN, -ESRCH, -ENOENT))
log_unit_warning_errno(u, r, "Failed to kill control group %s, ignoring: %m", u->cgroup_path);
} else if (r > 0) {
@@ -3957,7 +4199,7 @@ int unit_kill_context(
* them. */
if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0 ||
- (detect_container() == 0 && !unit_cgroup_delegate(u)))
+ (detect_container() == 0 && !UNIT_CGROUP_BOOL(u, delegate)))
wait_for_exit = true;
if (send_sighup) {
@@ -4129,6 +4371,7 @@ void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
log_struct(LOG_NOTICE,
"MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
"WHERE=%s", where,
NULL);
@@ -4151,6 +4394,7 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
log_struct(LOG_ERR,
"MESSAGE_ID=" SD_MESSAGE_OVERMOUNTING_STR,
LOG_UNIT_ID(u),
+ LOG_UNIT_INVOCATION_ID(u),
LOG_UNIT_MESSAGE(u, "Mount on symlink %s not allowed.", where),
"WHERE=%s", where,
NULL);
@@ -4388,3 +4632,51 @@ int unit_acquire_invocation_id(Unit *u) {
return 0;
}
+
+void unit_set_exec_params(Unit *u, ExecParameters *p) {
+ assert(u);
+ assert(p);
+
+ p->cgroup_path = u->cgroup_path;
+ SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
+}
+
+int unit_fork_helper_process(Unit *u, pid_t *ret) {
+ pid_t pid;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ /* Forks off a helper process and makes sure it is a member of the unit's cgroup. Returns == 0 in the child,
+ * and > 0 in the parent. The pid parameter is always filled in with the child's PID. */
+
+ (void) unit_realize_cgroup(u);
+
+ pid = fork();
+ if (pid < 0)
+ return -errno;
+
+ if (pid == 0) {
+
+ (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
+ (void) ignore_signals(SIGPIPE, -1);
+
+ log_close();
+ log_open();
+
+ if (u->cgroup_path) {
+ r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
+ if (r < 0) {
+ log_unit_error_errno(u, r, "Failed to join unit cgroup %s: %m", u->cgroup_path);
+ _exit(EXIT_CGROUP);
+ }
+ }
+
+ *ret = getpid_cached();
+ return 0;
+ }
+
+ *ret = pid;
+ return 1;
+}
diff --git a/src/core/unit.h b/src/core/unit.h
index cbca6a87e1..ded0edc8e2 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -28,11 +28,13 @@ typedef struct UnitVTable UnitVTable;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
+#include "bpf-program.h"
#include "condition.h"
#include "emergency-action.h"
#include "install.h"
#include "list.h"
#include "unit-name.h"
+#include "cgroup.h"
typedef enum KillOperation {
KILL_TERMINATE,
@@ -44,19 +46,19 @@ typedef enum KillOperation {
} KillOperation;
static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {
- return t == UNIT_ACTIVE || t == UNIT_RELOADING;
+ return IN_SET(t, UNIT_ACTIVE, UNIT_RELOADING);
}
static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
- return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING;
+ return IN_SET(t, UNIT_ACTIVE, UNIT_ACTIVATING, UNIT_RELOADING);
}
static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
- return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING;
+ return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED, UNIT_DEACTIVATING);
}
static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
- return t == UNIT_INACTIVE || t == UNIT_FAILED;
+ return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED);
}
#include "job.h"
@@ -70,6 +72,12 @@ struct UnitRef {
LIST_FIELDS(UnitRef, refs);
};
+typedef enum UnitCGroupBPFState {
+ UNIT_CGROUP_BPF_OFF = 0,
+ UNIT_CGROUP_BPF_ON = 1,
+ UNIT_CGROUP_BPF_INVALIDATED = -1,
+} UnitCGroupBPFState;
+
struct Unit {
Manager *manager;
@@ -115,6 +123,7 @@ struct Unit {
/* Job timeout and action to take */
usec_t job_timeout;
usec_t job_running_timeout;
+ bool job_running_timeout_set:1;
EmergencyAction job_timeout_action;
char *job_timeout_reboot_arg;
@@ -158,10 +167,10 @@ struct Unit {
LIST_FIELDS(Unit, gc_queue);
/* CGroup realize members queue */
- LIST_FIELDS(Unit, cgroup_queue);
+ LIST_FIELDS(Unit, cgroup_realize_queue);
- /* Units with the same CGroup netclass */
- LIST_FIELDS(Unit, cgroup_netclass);
+ /* cgroup empty queue */
+ LIST_FIELDS(Unit, cgroup_empty_queue);
/* PIDs we keep an eye on. Note that a unit might have many
* more, but these are the ones we care enough about to
@@ -205,6 +214,20 @@ struct Unit {
CGroupMask cgroup_members_mask;
int cgroup_inotify_wd;
+ /* IP BPF Firewalling/accounting */
+ int ip_accounting_ingress_map_fd;
+ int ip_accounting_egress_map_fd;
+
+ int ipv4_allow_map_fd;
+ int ipv6_allow_map_fd;
+ int ipv4_deny_map_fd;
+ int ipv6_deny_map_fd;
+
+ BPFProgram *ip_bpf_ingress;
+ BPFProgram *ip_bpf_egress;
+
+ uint64_t ip_accounting_extra[_CGROUP_IP_ACCOUNTING_METRIC_MAX];
+
/* How to start OnFailure units */
JobMode on_failure_job_mode;
@@ -244,7 +267,8 @@ struct Unit {
bool in_dbus_queue:1;
bool in_cleanup_queue:1;
bool in_gc_queue:1;
- bool in_cgroup_queue:1;
+ bool in_cgroup_realize_queue:1;
+ bool in_cgroup_empty_queue:1;
bool sent_dbus_new_signal:1;
@@ -254,6 +278,8 @@ struct Unit {
bool cgroup_members_mask_valid:1;
bool cgroup_subtree_mask_valid:1;
+ UnitCGroupBPFState cgroup_bpf_state:2;
+
bool start_limit_hit:1;
/* Did we already invoke unit_coldplug() for this unit? */
@@ -276,7 +302,6 @@ typedef enum UnitSetPropertiesMode {
} UnitSetPropertiesMode;
#include "automount.h"
-#include "busname.h"
#include "device.h"
#include "path.h"
#include "scope.h"
@@ -471,7 +496,6 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
DEFINE_CAST(SERVICE, Service);
DEFINE_CAST(SOCKET, Socket);
-DEFINE_CAST(BUSNAME, BusName);
DEFINE_CAST(TARGET, Target);
DEFINE_CAST(DEVICE, Device);
DEFINE_CAST(MOUNT, Mount);
@@ -565,6 +589,7 @@ bool unit_can_serialize(Unit *u) _pure_;
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+void unit_deserialize_skip(FILE *f);
int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
@@ -660,6 +685,10 @@ int unit_acquire_invocation_id(Unit *u);
bool unit_shall_confirm_spawn(Unit *u);
+void unit_set_exec_params(Unit *s, ExecParameters *p);
+
+int unit_fork_helper_process(Unit *u, pid_t *ret);
+
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
@@ -683,3 +712,4 @@ bool unit_shall_confirm_spawn(Unit *u);
#define LOG_UNIT_MESSAGE(unit, fmt, ...) "MESSAGE=%s: " fmt, (unit)->id, ##__VA_ARGS__
#define LOG_UNIT_ID(unit) (unit)->manager->unit_log_format_string, (unit)->id
+#define LOG_UNIT_INVOCATION_ID(unit) (unit)->manager->invocation_log_format_string, (unit)->invocation_id_string
diff --git a/src/coredump/Makefile b/src/coredump/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/coredump/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index a2c62e55a5..300d647903 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -23,7 +23,7 @@
#include <sys/xattr.h>
#include <unistd.h>
-#ifdef HAVE_ELFUTILS
+#if HAVE_ELFUTILS
#include <dwarf.h>
#include <elfutils/libdwfl.h>
#endif
@@ -156,7 +156,7 @@ static inline uint64_t storage_size_max(void) {
static int fix_acl(int fd, uid_t uid) {
-#ifdef HAVE_ACL
+#if HAVE_ACL
_cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
acl_permset_t permset;
@@ -393,7 +393,7 @@ static int save_external_coredump(
goto fail;
}
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
/* If we will remove the coredump anyway, do not compress. */
if (arg_compress && !maybe_remove_external_coredump(NULL, st.st_size)) {
@@ -564,7 +564,7 @@ static int compose_open_fds(pid_t pid, char **open_fds) {
}
FOREACH_LINE(line, fdinfo, break) {
- fputs(line, stream);
+ fputs_unlocked(line, stream);
if (!endswith(line, "\n"))
fputc('\n', stream);
}
@@ -749,7 +749,7 @@ static int submit_coredump(
const char *coredump_filename;
coredump_filename = strjoina("COREDUMP_FILENAME=", filename);
- IOVEC_SET_STRING(iovec[n_iovec++], coredump_filename);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(coredump_filename);
} else if (arg_storage == COREDUMP_STORAGE_EXTERNAL)
log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
coredump_size, arg_external_size_max);
@@ -765,7 +765,7 @@ static int submit_coredump(
if (r < 0)
return log_error_errno(r, "Failed to drop privileges: %m");
-#ifdef HAVE_ELFUTILS
+#if HAVE_ELFUTILS
/* Try to get a strack trace if we can */
if (coredump_size <= arg_process_size_max) {
_cleanup_free_ char *stacktrace = NULL;
@@ -804,10 +804,10 @@ log:
return 0;
}
- IOVEC_SET_STRING(iovec[n_iovec++], core_message);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(core_message);
if (truncated)
- IOVEC_SET_STRING(iovec[n_iovec++], "COREDUMP_TRUNCATED=1");
+ iovec[n_iovec++] = IOVEC_MAKE_STRING("COREDUMP_TRUNCATED=1");
/* Optionally store the entire coredump in the journal */
if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
@@ -817,11 +817,9 @@ log:
/* Store the coredump itself in the journal */
r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz);
- if (r >= 0) {
- iovec[n_iovec].iov_base = coredump_data;
- iovec[n_iovec].iov_len = sz;
- n_iovec++;
- } else
+ if (r >= 0)
+ iovec[n_iovec++] = IOVEC_MAKE(coredump_data, sz);
+ else
log_warning_errno(r, "Failed to attach the core to the journal entry: %m");
} else
log_info("The core will not be stored: size %"PRIu64" is greater than %"PRIu64" (the configured maximum)",
@@ -1070,7 +1068,7 @@ static char* set_iovec_field(struct iovec iovec[27], size_t *n_iovec, const char
x = strappend(field, value);
if (x)
- IOVEC_SET_STRING(iovec[(*n_iovec)++], x);
+ iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
return x;
}
@@ -1162,7 +1160,7 @@ static int gather_pid_metadata(
if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
r = asprintf(&t, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid);
if (r > 0)
- IOVEC_SET_STRING(iovec[(*n_iovec)++], t);
+ iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
}
if (sd_pid_get_slice(pid, &t) >= 0)
@@ -1218,7 +1216,7 @@ static int gather_pid_metadata(
t = strjoin("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL);
if (t)
- IOVEC_SET_STRING(iovec[(*n_iovec)++], t);
+ iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(t);
if (safe_atoi(context[CONTEXT_SIGNAL], &signo) >= 0 && SIGNAL_VALID(signo))
set_iovec_field(iovec, n_iovec, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(signo));
@@ -1253,10 +1251,10 @@ static int process_kernel(int argc, char* argv[]) {
n_iovec = n_to_free;
- IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING("MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
assert_cc(2 == LOG_CRIT);
- IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2");
+ iovec[n_iovec++] = IOVEC_MAKE_STRING("PRIORITY=2");
assert(n_iovec <= ELEMENTSOF(iovec));
@@ -1344,15 +1342,15 @@ static int process_backtrace(int argc, char *argv[]) {
r = log_oom();
goto finish;
}
- IOVEC_SET_STRING(iovec[n_iovec++], message);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING(message);
} else {
for (i = 0; i < importer.iovw.count; i++)
iovec[n_iovec++] = importer.iovw.iovec[i];
}
- IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
+ iovec[n_iovec++] = IOVEC_MAKE_STRING("MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
assert_cc(2 == LOG_CRIT);
- IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2");
+ iovec[n_iovec++] = IOVEC_MAKE_STRING("PRIORITY=2");
assert(n_iovec <= n_allocated);
diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c
index 114a13fc78..0380df10d1 100644
--- a/src/coredump/coredumpctl.c
+++ b/src/coredump/coredumpctl.c
@@ -799,7 +799,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
}
if (filename) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
_cleanup_close_ int fdf;
fdf = open(filename, O_RDONLY | O_CLOEXEC);
diff --git a/src/coredump/meson.build b/src/coredump/meson.build
index 8f7d898b62..25a0409046 100644
--- a/src/coredump/meson.build
+++ b/src/coredump/meson.build
@@ -4,7 +4,7 @@ systemd_coredump_sources = files('''
coredump-vacuum.h
'''.split())
-if conf.get('HAVE_ELFUTILS', false)
+if conf.get('HAVE_ELFUTILS') == 1
systemd_coredump_sources += files(['stacktrace.c',
'stacktrace.h'])
endif
diff --git a/src/coredump/stacktrace.c b/src/coredump/stacktrace.c
index 778bee9b12..1726613623 100644
--- a/src/coredump/stacktrace.c
+++ b/src/coredump/stacktrace.c
@@ -107,7 +107,7 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) {
return DWARF_CB_ABORT;
if (c->n_thread != 0)
- fputc('\n', c->f);
+ fputc_unlocked('\n', c->f);
c->n_frame = 0;
diff --git a/src/cryptsetup/Makefile b/src/cryptsetup/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/cryptsetup/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index b58b6db7c9..3752ca2ef2 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -58,11 +58,11 @@ static int create_disk(
const char *password,
const char *options) {
- _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL,
+ _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *e = NULL,
*filtered = NULL;
_cleanup_fclose_ FILE *f = NULL;
- bool noauto, nofail, tmp, swap;
- char *from;
+ const char *dmname;
+ bool noauto, nofail, tmp, swap, netdev;
int r;
assert(name);
@@ -72,6 +72,7 @@ static int create_disk(
nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
tmp = fstab_test_option(options, "tmp\0");
swap = fstab_test_option(options, "swap\0");
+ netdev = fstab_test_option(options, "_netdev\0");
if (tmp && swap) {
log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
@@ -102,26 +103,27 @@ static int create_disk(
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
- fputs("# Automatically generated by systemd-cryptsetup-generator\n\n"
- "[Unit]\n"
- "Description=Cryptography Setup for %I\n"
- "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
- "SourcePath=/etc/crypttab\n"
- "DefaultDependencies=no\n"
- "Conflicts=umount.target\n"
- "BindsTo=dev-mapper-%i.device\n"
- "IgnoreOnIsolate=true\n"
- "After=cryptsetup-pre.target\n",
- f);
+ fprintf(f,
+ "# Automatically generated by systemd-cryptsetup-generator\n\n"
+ "[Unit]\n"
+ "Description=Cryptography Setup for %%I\n"
+ "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
+ "SourcePath=/etc/crypttab\n"
+ "DefaultDependencies=no\n"
+ "Conflicts=umount.target\n"
+ "IgnoreOnIsolate=true\n"
+ "After=%s\n",
+ netdev ? "remote-cryptsetup-pre.target" : "cryptsetup-pre.target");
if (!nofail)
fprintf(f,
- "Before=cryptsetup.target\n");
+ "Before=%s\n",
+ netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
if (password) {
if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
- fputs("After=systemd-random-seed.service\n", f);
- else if (!streq(password, "-") && !streq(password, "none")) {
+ fputs_unlocked("After=systemd-random-seed.service\n", f);
+ else if (!STR_IN_SET(password, "-", "none")) {
_cleanup_free_ char *uu;
uu = fstab_node_to_udev_node(password);
@@ -130,7 +132,7 @@ static int create_disk(
if (!path_equal(uu, "/dev/null")) {
- if (is_device_path(uu)) {
+ if (path_startswith(uu, "/dev/")) {
_cleanup_free_ char *dd = NULL;
r = unit_name_from_path(uu, ".device", &dd);
@@ -144,7 +146,7 @@ static int create_disk(
}
}
- if (is_device_path(u)) {
+ if (path_startswith(u, "/dev/")) {
fprintf(f,
"BindsTo=%s\n"
"After=%s\n"
@@ -152,8 +154,8 @@ static int create_disk(
d, d);
if (swap)
- fputs("Before=dev-mapper-%i.swap\n",
- f);
+ fputs_unlocked("Before=dev-mapper-%i.swap\n",
+ f);
} else
fprintf(f,
"RequiresMountsFor=%s\n",
@@ -168,6 +170,7 @@ static int create_disk(
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
+ "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
name, u, strempty(password), strempty(filtered),
@@ -187,46 +190,24 @@ static int create_disk(
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", p);
- from = strjoina("../", n);
-
if (!noauto) {
+ r = generator_add_symlink(arg_dest, d, "wants", n);
+ if (r < 0)
+ return r;
- to = strjoin(arg_dest, "/", d, ".wants/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
-
- free(to);
- if (!nofail)
- to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
- else
- to = strjoin(arg_dest, "/cryptsetup.target.wants/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ r = generator_add_symlink(arg_dest,
+ netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
+ nofail ? "wants" : "requires", n);
+ if (r < 0)
+ return r;
}
- free(to);
- to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ dmname = strjoina("dev-mapper-", e, ".device");
+ r = generator_add_symlink(arg_dest, dmname, "requires", n);
+ if (r < 0)
+ return r;
if (!noauto && !nofail) {
- _cleanup_free_ char *dmname;
- dmname = strjoin("dev-mapper-", e, ".device");
- if (!dmname)
- return log_oom();
-
r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator \n\n"
"[Unit]\nJobTimeoutSec=0");
@@ -397,7 +378,7 @@ static int add_crypttab_devices(void) {
crypttab_line++;
l = strstrip(line);
- if (*l == '#' || *l == 0)
+ if (IN_SET(*l, 0, '#'))
continue;
k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyfile, &options);
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 3b4c086162..8fc35ad999 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -52,11 +52,13 @@ static bool arg_verify = false;
static bool arg_discards = false;
static bool arg_tcrypt_hidden = false;
static bool arg_tcrypt_system = false;
+#ifdef CRYPT_TCRYPT_VERA_MODES
static bool arg_tcrypt_veracrypt = false;
+#endif
static char **arg_tcrypt_keyfiles = NULL;
static uint64_t arg_offset = 0;
static uint64_t arg_skip = 0;
-static usec_t arg_timeout = 0;
+static usec_t arg_timeout = USEC_INFINITY;
/* Options Debian's crypttab knows we don't:
@@ -658,7 +660,7 @@ int main(int argc, char *argv[]) {
crypt_set_log_callback(cd, log_glue, NULL);
status = crypt_status(cd, argv[2]);
- if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
+ if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
log_info("Volume %s already active.", argv[2]);
r = 0;
goto finish;
@@ -670,10 +672,10 @@ int main(int argc, char *argv[]) {
if (arg_discards)
flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
- if (arg_timeout > 0)
- until = now(CLOCK_MONOTONIC) + arg_timeout;
- else
+ if (arg_timeout == USEC_INFINITY)
until = 0;
+ else
+ until = now(CLOCK_MONOTONIC) + arg_timeout;
arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
diff --git a/src/dbus1-generator/Makefile b/src/dbus1-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/dbus1-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/debug-generator/Makefile b/src/debug-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/debug-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/delta/Makefile b/src/delta/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/delta/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/delta/delta.c b/src/delta/delta.c
index b0689ffff7..605bea57bb 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -49,7 +49,7 @@ static const char prefixes[] =
"/usr/local/share\0"
"/usr/lib\0"
"/usr/share\0"
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib\0"
#endif
;
@@ -392,7 +392,7 @@ static int enumerate_dir(
}
static int should_skip_prefix(const char* p) {
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
int r;
_cleanup_free_ char *target = NULL;
diff --git a/src/detect-virt/Makefile b/src/detect-virt/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/detect-virt/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/dissect/Makefile b/src/dissect/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/dissect/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/environment-d-generator/Makefile b/src/environment-d-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/environment-d-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/environment-d-generator/environment-d-generator.c b/src/environment-d-generator/environment-d-generator.c
index 9c72502373..55de68550d 100644
--- a/src/environment-d-generator/environment-d-generator.c
+++ b/src/environment-d-generator/environment-d-generator.c
@@ -58,7 +58,7 @@ static int load_and_print(void) {
if (r < 0)
return r;
- r = conf_files_list_strv(&files, ".conf", NULL, (const char **) dirs);
+ r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char **) dirs);
if (r < 0)
return r;
diff --git a/src/escape/Makefile b/src/escape/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/escape/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/escape/escape.c b/src/escape/escape.c
index af98c98e40..5518c2a6fa 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -38,7 +38,7 @@ static bool arg_path = false;
static void help(void) {
printf("%s [OPTIONS...] [NAME...]\n\n"
- "Show system and user paths.\n\n"
+ "Escape strings for usage in systemd unit names.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --suffix=SUFFIX Unit suffix to append to escaped strings\n"
diff --git a/src/firstboot/Makefile b/src/firstboot/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/firstboot/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index b3578d3e16..586674d458 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -411,7 +411,8 @@ static int process_hostname(void) {
return 0;
mkdir_parents(etc_hostname, 0755);
- r = write_string_file(etc_hostname, arg_hostname, WRITE_STRING_FILE_CREATE);
+ r = write_string_file(etc_hostname, arg_hostname,
+ WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC);
if (r < 0)
return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
@@ -432,7 +433,8 @@ static int process_machine_id(void) {
return 0;
mkdir_parents(etc_machine_id, 0755);
- r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id), WRITE_STRING_FILE_CREATE);
+ r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id),
+ WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC);
if (r < 0)
return log_error_errno(r, "Failed to write machine id: %m");
@@ -503,7 +505,7 @@ static int write_root_shadow(const char *path, const struct spwd *p) {
if (putspent(p, f) != 0)
return errno > 0 ? -errno : -EIO;
- return fflush_and_check(f);
+ return fflush_sync_and_check(f);
}
static int process_root_password(void) {
diff --git a/src/fsck/Makefile b/src/fsck/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/fsck/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 2100681e17..cf5a9c59ff 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -131,7 +131,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
}
}
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
else if (streq(key, "fastboot") && !value) {
log_warning("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
arg_skip = true;
@@ -147,7 +147,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
static void test_files(void) {
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
if (access("/fastboot", F_OK) >= 0) {
log_error("Please pass 'fsck.mode=skip' on the kernel command line rather than creating /fastboot on the root file system.");
arg_skip = true;
@@ -269,7 +269,7 @@ static int fsck_progress_socket(void) {
return log_warning_errno(errno, "socket(): %m");
if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
- r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
+ r = log_full_errno(IN_SET(errno, ECONNREFUSED, ENOENT) ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
safe_close(fd);
return r;
@@ -462,7 +462,7 @@ int main(int argc, char *argv[]) {
if (status.si_code != CLD_EXITED || (status.si_status & ~1)) {
- if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED)
+ if (IN_SET(status.si_code, CLD_KILLED, CLD_DUMPED))
log_error("fsck terminated by signal %s.", signal_to_string(status.si_status));
else if (status.si_code == CLD_EXITED)
log_error("fsck failed with error code %i.", status.si_status);
diff --git a/src/fstab-generator/Makefile b/src/fstab-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/fstab-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 7f23b9fd74..ec70a349fc 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -92,7 +92,7 @@ static int add_swap(
bool noauto,
bool nofail) {
- _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
+ _cleanup_free_ char *name = NULL, *unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -125,11 +125,11 @@ static int add_swap(
"Failed to create unit file %s: %m",
unit);
- fputs("# Automatically generated by systemd-fstab-generator\n\n"
- "[Unit]\n"
- "SourcePath=/etc/fstab\n"
- "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
- "[Swap]\n", f);
+ fputs_unlocked("# Automatically generated by systemd-fstab-generator\n\n"
+ "[Unit]\n"
+ "SourcePath=/etc/fstab\n"
+ "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
+ "[Swap]\n", f);
r = write_what(f, what);
if (r < 0)
@@ -149,14 +149,10 @@ static int add_swap(
return r;
if (!noauto) {
- lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
- nofail ? ".wants/" : ".requires/", name, NULL);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
+ nofail ? "wants" : "requires", name);
+ if (r < 0)
+ return r;
}
return 0;
@@ -302,7 +298,7 @@ static int add_mount(
const char *source) {
_cleanup_free_ char
- *name = NULL, *unit = NULL, *lnk = NULL,
+ *name = NULL, *unit = NULL,
*automount_name = NULL, *automount_unit = NULL,
*filtered = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -431,13 +427,10 @@ static int add_mount(
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
if (!noauto && !automount) {
- lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", name);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(dest, post,
+ nofail ? "wants" : "requires", name);
+ if (r < 0)
+ return r;
}
if (automount) {
@@ -492,14 +485,10 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
- free(lnk);
- lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(automount_unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(dest, post,
+ nofail ? "wants" : "requires", automount_name);
+ if (r < 0)
+ return r;
}
return 0;
@@ -537,7 +526,7 @@ static int parse_fstab(bool initrd) {
continue;
}
- where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
+ where = strdup(me->mnt_dir);
if (!where)
return log_oom();
diff --git a/src/getty-generator/Makefile b/src/getty-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/getty-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index b15c76b5b8..a143b5413b 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -201,16 +201,16 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
+ /* We assume that gettys on virtual terminals are
+ * started via manual configuration and do this magic
+ * only for non-VC terminals. */
+
if (isempty(tty) || tty_is_vc(tty))
continue;
if (verify_tty(tty) < 0)
continue;
- /* We assume that gettys on virtual terminals are
- * started via manual configuration and do this magic
- * only for non-VC terminals. */
-
if (add_serial_getty(tty) < 0)
return EXIT_FAILURE;
}
diff --git a/src/gpt-auto-generator/Makefile b/src/gpt-auto-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/gpt-auto-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index a072242430..ae0a8da63a 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -58,7 +58,7 @@ static bool arg_root_rw = false;
static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
_cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
_cleanup_fclose_ FILE *f = NULL;
- char *from, *ret;
+ char *ret;
int r;
assert(id);
@@ -99,6 +99,7 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, bool requir
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
+ "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
d, d,
@@ -109,35 +110,21 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, bool requir
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", p);
- from = strjoina("../", n);
-
- to = strjoin(arg_dest, "/", d, ".wants/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ r = generator_add_symlink(arg_dest, d, "wants", n);
+ if (r < 0)
+ return r;
if (require) {
- free(to);
+ const char *dmname;
- to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
-
- free(to);
- to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
- if (!to)
- return log_oom();
+ r = generator_add_symlink(arg_dest, "cryptsetup.target", "requires", n);
+ if (r < 0)
+ return r;
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ dmname = strjoina("dev-mapper-", e, ".device");
+ r = generator_add_symlink(arg_dest, dmname, "requires", n);
+ if (r < 0)
+ return r;
}
free(p);
@@ -173,7 +160,7 @@ static int add_mount(
const char *description,
const char *post) {
- _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
+ _cleanup_free_ char *unit = NULL, *crypto_what = NULL, *p = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -239,16 +226,8 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", p);
- if (post) {
- lnk = strjoin(arg_dest, "/", post, ".requires/", unit);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(p, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
- }
-
+ if (post)
+ return generator_add_symlink(arg_dest, post, "requires", unit);
return 0;
}
@@ -299,7 +278,7 @@ static int add_partition_mount(
}
static int add_swap(const char *path) {
- _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
+ _cleanup_free_ char *name = NULL, *unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -341,18 +320,10 @@ static int add_swap(const char *path) {
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
- lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
-
- return 0;
+ return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
}
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
static int add_automount(
const char *id,
const char *what,
@@ -363,7 +334,7 @@ static int add_automount(
const char *description,
usec_t timeout) {
- _cleanup_free_ char *unit = NULL, *lnk = NULL;
+ _cleanup_free_ char *unit = NULL;
_cleanup_free_ char *opt, *p = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@@ -418,15 +389,7 @@ static int add_automount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", p);
- lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit);
- if (!lnk)
- return log_oom();
- mkdir_parents_label(lnk, 0755);
-
- if (symlink(p, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
-
- return 0;
+ return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
}
static int add_esp(DissectedPartition *p) {
@@ -609,136 +572,6 @@ static int enumerate_partitions(dev_t devnum) {
return r;
}
-static int get_block_device(const char *path, dev_t *dev) {
- struct stat st;
- struct statfs sfs;
-
- assert(path);
- assert(dev);
-
- /* Get's the block device directly backing a file system. If
- * the block device is encrypted, returns the device mapper
- * block device. */
-
- if (lstat(path, &st))
- return -errno;
-
- if (major(st.st_dev) != 0) {
- *dev = st.st_dev;
- return 1;
- }
-
- if (statfs(path, &sfs) < 0)
- return -errno;
-
- if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
- return btrfs_get_block_device(path, dev);
-
- return 0;
-}
-
-static int get_block_device_harder(const char *path, dev_t *dev) {
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *p = NULL, *t = NULL;
- struct dirent *de, *found = NULL;
- const char *q;
- unsigned maj, min;
- dev_t dt;
- int r;
-
- assert(path);
- assert(dev);
-
- /* Gets the backing block device for a file system, and
- * handles LUKS encrypted file systems, looking for its
- * immediate parent, if there is one. */
-
- r = get_block_device(path, &dt);
- if (r <= 0)
- return r;
-
- if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
- return -ENOMEM;
-
- d = opendir(p);
- if (!d) {
- if (errno == ENOENT)
- goto fallback;
-
- return -errno;
- }
-
- FOREACH_DIRENT_ALL(de, d, return -errno) {
-
- if (dot_or_dot_dot(de->d_name))
- continue;
-
- if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
- continue;
-
- if (found) {
- _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
-
- /* We found a device backed by multiple other devices. We don't really support automatic
- * discovery on such setups, with the exception of dm-verity partitions. In this case there are
- * two backing devices: the data partition and the hash partition. We are fine with such
- * setups, however, only if both partitions are on the same physical device. Hence, let's
- * verify this. */
-
- u = strjoin(p, "/", de->d_name, "/../dev");
- if (!u)
- return -ENOMEM;
-
- v = strjoin(p, "/", found->d_name, "/../dev");
- if (!v)
- return -ENOMEM;
-
- r = read_one_line_file(u, &a);
- if (r < 0) {
- log_debug_errno(r, "Failed to read %s: %m", u);
- goto fallback;
- }
-
- r = read_one_line_file(v, &b);
- if (r < 0) {
- log_debug_errno(r, "Failed to read %s: %m", v);
- goto fallback;
- }
-
- /* Check if the parent device is the same. If not, then the two backing devices are on
- * different physical devices, and we don't support that. */
- if (!streq(a, b))
- goto fallback;
- }
-
- found = de;
- }
-
- if (!found)
- goto fallback;
-
- q = strjoina(p, "/", found->d_name, "/dev");
-
- r = read_one_line_file(q, &t);
- if (r == -ENOENT)
- goto fallback;
- if (r < 0)
- return r;
-
- if (sscanf(t, "%u:%u", &maj, &min) != 2)
- return -EINVAL;
-
- if (maj == 0)
- goto fallback;
-
- *dev = makedev(maj, min);
- return 1;
-
-fallback:
- *dev = dt;
- return 1;
-}
-
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
int r;
@@ -779,7 +612,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
return 0;
}
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
static int add_root_cryptsetup(void) {
/* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
@@ -791,7 +624,7 @@ static int add_root_cryptsetup(void) {
static int add_root_mount(void) {
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
int r;
if (!is_efi_boot()) {
diff --git a/src/hibernate-resume/Makefile b/src/hibernate-resume/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/hibernate-resume/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/hostname/.gitignore b/src/hostname/.gitignore
deleted file mode 100644
index 1ff281b231..0000000000
--- a/src/hostname/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-org.freedesktop.hostname1.policy
diff --git a/src/hostname/Makefile b/src/hostname/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/hostname/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/hostname/meson.build b/src/hostname/meson.build
index d58caa6787..834300ae6e 100644
--- a/src/hostname/meson.build
+++ b/src/hostname/meson.build
@@ -1,4 +1,4 @@
-if conf.get('ENABLE_HOSTNAMED', false)
+if conf.get('ENABLE_HOSTNAMED') == 1
install_data('org.freedesktop.hostname1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.hostname1.service',
diff --git a/src/hwdb/Makefile b/src/hwdb/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/hwdb/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 793398ca68..c964a28bce 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -403,14 +403,14 @@ static int trie_store(struct trie *trie, const char *filename) {
t.strings_off = sizeof(struct trie_header_f);
trie_store_nodes_size(&t, trie->root);
- r = fopen_temporary(filename , &t.f, &filename_tmp);
+ r = fopen_temporary(filename, &t.f, &filename_tmp);
if (r < 0)
return r;
fchmod(fileno(t.f), 0444);
/* write nodes */
if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
- goto error;
+ goto error_fclose;
root_off = trie_store_nodes(&t, trie->root);
h.nodes_root_off = htole64(root_off);
@@ -425,13 +425,20 @@ static int trie_store(struct trie *trie, const char *filename) {
size = ftello(t.f);
h.file_size = htole64(size);
if (fseeko(t.f, 0, SEEK_SET) < 0)
- goto error;
-
+ goto error_fclose;
fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
- if (fclose(t.f) < 0 || rename(filename_tmp, filename) < 0) {
- unlink_noerrno(filename_tmp);
- return -errno;
- }
+
+ if (ferror(t.f))
+ goto error_fclose;
+ if (fflush(t.f) < 0)
+ goto error_fclose;
+ if (fsync(fileno(t.f)) < 0)
+ goto error_fclose;
+ if (rename(filename_tmp, filename) < 0)
+ goto error_fclose;
+
+ /* write succeeded */
+ fclose(t.f);
log_debug("=== trie on-disk ===");
log_debug("size: %8"PRIi64" bytes", size);
@@ -446,7 +453,7 @@ static int trie_store(struct trie *trie, const char *filename) {
log_debug("strings start: %8"PRIu64, t.strings_off);
return 0;
- error:
+ error_fclose:
r = -errno;
fclose(t.f);
unlink(filename_tmp);
@@ -646,7 +653,7 @@ static int hwdb_update(int argc, char *argv[], void *userdata) {
trie->nodes_count++;
- r = conf_files_list_strv(&files, ".hwdb", arg_root, conf_file_dirs);
+ r = conf_files_list_strv(&files, ".hwdb", arg_root, 0, conf_file_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate hwdb files: %m");
diff --git a/src/import/.gitignore b/src/import/.gitignore
deleted file mode 100644
index 01106e2e68..0000000000
--- a/src/import/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/org.freedesktop.import1.policy
diff --git a/src/import/Makefile b/src/import/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/import/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/import/import-common.c b/src/import/import-common.c
index 81209cdaf6..ae71682988 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -37,7 +37,7 @@ int import_make_read_only_fd(int fd) {
/* First, let's make this a read-only subvolume if it refers
* to a subvolume */
r = btrfs_subvol_set_read_only_fd(fd, true);
- if (r == -ENOTTY || r == -ENOTDIR || r == -EINVAL) {
+ if (IN_SET(r, -ENOTTY, -ENOTDIR, -EINVAL)) {
struct stat st;
/* This doesn't refer to a subvolume, or the file
diff --git a/src/import/import-compress.c b/src/import/import-compress.c
index f1766bbe3b..01b78fc9a6 100644
--- a/src/import/import-compress.c
+++ b/src/import/import-compress.c
@@ -135,7 +135,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->xz.avail_out = sizeof(buffer);
lzr = lzma_code(&c->xz, LZMA_RUN);
- if (lzr != LZMA_OK && lzr != LZMA_STREAM_END)
+ if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
return -EIO;
r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata);
@@ -156,7 +156,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->gzip.avail_out = sizeof(buffer);
r = inflate(&c->gzip, Z_NO_FLUSH);
- if (r != Z_OK && r != Z_STREAM_END)
+ if (!IN_SET(r, Z_OK, Z_STREAM_END))
return -EIO;
r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata);
@@ -177,7 +177,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->bzip2.avail_out = sizeof(buffer);
r = BZ2_bzDecompress(&c->bzip2);
- if (r != BZ_OK && r != BZ_STREAM_END)
+ if (!IN_SET(r, BZ_OK, BZ_STREAM_END))
return -EIO;
r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata);
@@ -399,7 +399,7 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
c->xz.avail_out = *buffer_allocated - *buffer_size;
lzr = lzma_code(&c->xz, LZMA_FINISH);
- if (lzr != LZMA_OK && lzr != LZMA_STREAM_END)
+ if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
return -EIO;
*buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
@@ -420,7 +420,7 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
c->gzip.avail_out = *buffer_allocated - *buffer_size;
r = deflate(&c->gzip, Z_FINISH);
- if (r != Z_OK && r != Z_STREAM_END)
+ if (!IN_SET(r, Z_OK, Z_STREAM_END))
return -EIO;
*buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
@@ -440,7 +440,7 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
c->bzip2.avail_out = *buffer_allocated - *buffer_size;
r = BZ2_bzCompress(&c->bzip2, BZ_FINISH);
- if (r != BZ_FINISH_OK && r != BZ_STREAM_END)
+ if (!IN_SET(r, BZ_FINISH_OK, BZ_STREAM_END))
return -EIO;
*buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
diff --git a/src/import/importd.c b/src/import/importd.c
index 3d379d6de9..9b3fd06b52 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -250,7 +250,7 @@ static void transfer_send_logs(Transfer *t, bool flush) {
n = strndup(t->log_message, e - t->log_message);
/* Skip over NUL and newlines */
- while ((e < t->log_message + t->log_message_size) && (*e == 0 || *e == '\n'))
+ while ((e < t->log_message + t->log_message_size) && IN_SET(*e, 0, '\n'))
e++;
memmove(t->log_message, e, t->log_message + sizeof(t->log_message) - e);
@@ -321,8 +321,7 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda
success = true;
}
- } else if (si->si_code == CLD_KILLED ||
- si->si_code == CLD_DUMPED)
+ } else if (IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED))
log_error("Import process terminated by signal %s.", signal_to_string(si->si_status));
else
@@ -418,7 +417,7 @@ static int transfer_start(Transfer *t) {
}
}
- if (pipefd[1] != STDOUT_FILENO && pipefd[1] != STDERR_FILENO)
+ if (!IN_SET(pipefd[1], STDOUT_FILENO, STDERR_FILENO))
pipefd[1] = safe_close(pipefd[1]);
if (t->stdin_fd >= 0) {
@@ -585,7 +584,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/import/meson.build b/src/import/meson.build
index 3fd58cc2c8..e3a0da65d2 100644
--- a/src/import/meson.build
+++ b/src/import/meson.build
@@ -48,7 +48,7 @@ systemd_export_sources = files('''
import-compress.h
'''.split())
-if conf.get('ENABLE_IMPORTD', false)
+if conf.get('ENABLE_IMPORTD') == 1
install_data('org.freedesktop.import1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.import1.service',
diff --git a/src/import/pull-job.c b/src/import/pull-job.c
index 320c21305a..995a652ec3 100644
--- a/src/import/pull-job.c
+++ b/src/import/pull-job.c
@@ -58,8 +58,7 @@ PullJob* pull_job_unref(PullJob *j) {
static void pull_job_finish(PullJob *j, int ret) {
assert(j);
- if (j->state == PULL_JOB_DONE ||
- j->state == PULL_JOB_FAILED)
+ if (IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED))
return;
if (ret == 0) {
@@ -109,7 +108,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
if (curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&j) != CURLE_OK)
return;
- if (!j || j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED)
+ if (!j || IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED))
return;
if (result != CURLE_OK) {
@@ -442,7 +441,7 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb
assert(contents);
assert(j);
- if (j->state == PULL_JOB_DONE || j->state == PULL_JOB_FAILED) {
+ if (IN_SET(j->state, PULL_JOB_DONE, PULL_JOB_FAILED)) {
r = -ESTALE;
goto fail;
}
diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c
index ee2121cc36..00734865b2 100644
--- a/src/import/qcow2-util.c
+++ b/src/import/qcow2-util.c
@@ -213,8 +213,7 @@ static int verify_header(const Header *header) {
if (HEADER_MAGIC(header) != QCOW2_MAGIC)
return -EBADMSG;
- if (HEADER_VERSION(header) != 2 &&
- HEADER_VERSION(header) != 3)
+ if (!IN_SET(HEADER_VERSION(header), 2, 3))
return -EOPNOTSUPP;
if (HEADER_CRYPT_METHOD(header) != 0)
diff --git a/src/initctl/Makefile b/src/initctl/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/initctl/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index 6aeb5ad614..deb3f1b2a8 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -388,7 +388,7 @@ int main(int argc, char *argv[]) {
if (server_init(&server, (unsigned) n) < 0)
return EXIT_FAILURE;
- log_debug("systemd-initctl running as pid "PID_FMT, getpid());
+ log_debug("systemd-initctl running as pid "PID_FMT, getpid_cached());
sd_notify(false,
"READY=1\n"
@@ -415,7 +415,7 @@ int main(int argc, char *argv[]) {
r = EXIT_SUCCESS;
- log_debug("systemd-initctl stopped as pid "PID_FMT, getpid());
+ log_debug("systemd-initctl stopped as pid "PID_FMT, getpid_cached());
fail:
sd_notify(false,
diff --git a/src/journal-remote/.gitignore b/src/journal-remote/.gitignore
deleted file mode 100644
index 06847b65d4..0000000000
--- a/src/journal-remote/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/journal-remote.conf
-/journal-upload.conf
diff --git a/src/journal-remote/Makefile b/src/journal-remote/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/journal-remote/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 9a1c5b76ca..a0f1f3e926 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -946,7 +946,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_TRUST:
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
if (arg_trust_pem) {
log_error("CA certificate file specified twice");
return -EINVAL;
@@ -1041,7 +1041,7 @@ int main(int argc, char *argv[]) {
MHD_USE_DEBUG |
MHD_USE_DUAL_STACK |
MHD_USE_ITC |
- MHD_USE_POLL |
+ MHD_USE_POLL_INTERNAL_THREAD |
MHD_USE_THREAD_PER_CONNECTION;
if (n > 0)
@@ -1053,10 +1053,10 @@ int main(int argc, char *argv[]) {
{MHD_OPTION_HTTPS_MEM_KEY, 0, arg_key_pem};
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_CERT, 0, arg_cert_pem};
- flags |= MHD_USE_SSL;
+ flags |= MHD_USE_TLS;
}
if (arg_trust_pem) {
- assert(flags & MHD_USE_SSL);
+ assert(flags & MHD_USE_TLS);
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem};
}
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index 36c1a32dcd..9f51137645 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -66,7 +66,7 @@ static int arg_seal = false;
static int http_socket = -1, https_socket = -1;
static char** arg_gnutls_log = NULL;
-static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
+static JournalWriteSplitMode arg_split_mode = _JOURNAL_WRITE_SPLIT_INVALID;
static char* arg_output = NULL;
static char *arg_key = NULL;
@@ -86,7 +86,7 @@ static int spawn_child(const char* child, char** argv) {
if (pipe(fd) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
- parent_pid = getpid();
+ parent_pid = getpid_cached();
child_pid = fork();
if (child_pid < 0) {
@@ -644,13 +644,13 @@ static int setup_microhttpd_server(RemoteServer *s,
{ MHD_OPTION_END},
{ MHD_OPTION_END},
{ MHD_OPTION_END},
+ { MHD_OPTION_END},
{ MHD_OPTION_END}};
int opts_pos = 4;
int flags =
MHD_USE_DEBUG |
MHD_USE_DUAL_STACK |
MHD_USE_EPOLL |
- MHD_USE_PEDANTIC_CHECKS |
MHD_USE_ITC;
const union MHD_DaemonInfo *info;
@@ -663,6 +663,20 @@ static int setup_microhttpd_server(RemoteServer *s,
if (r < 0)
return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
+/* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
+ * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
+ * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
+ * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
+ * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
+ * deprecated yet and there exists an enum element with the same name.
+ * So we can safely use it. */
+#ifdef MHD_USE_PEDANTIC_CHECKS
+ opts[opts_pos++] = (struct MHD_OptionItem)
+ {MHD_OPTION_STRICT_FOR_CLIENT, 1};
+#else
+ flags |= MHD_USE_PEDANTIC_CHECKS;
+#endif
+
if (key) {
assert(cert);
@@ -671,7 +685,7 @@ static int setup_microhttpd_server(RemoteServer *s,
opts[opts_pos++] = (struct MHD_OptionItem)
{MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
- flags |= MHD_USE_SSL;
+ flags |= MHD_USE_TLS;
if (trust)
opts[opts_pos++] = (struct MHD_OptionItem)
@@ -1370,7 +1384,7 @@ static int parse_argv(int argc, char *argv[]) {
if (streq(optarg, "all"))
arg_trust_all = true;
else {
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
arg_trust = strdup(optarg);
if (!arg_trust)
return log_oom();
@@ -1428,7 +1442,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_GNUTLS_LOG: {
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
const char* p = optarg;
for (;;) {
_cleanup_free_ char *word = NULL;
@@ -1478,13 +1492,26 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID)) {
+ log_error("For active sources, only --split-mode=none is allowed.");
+ return -EINVAL;
+ }
+
arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
}
- if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
- && arg_output && is_dir(arg_output, true) > 0) {
- log_error("For SplitMode=none, output must be a file.");
- return -EINVAL;
+ if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID)
+ arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
+
+ if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE && arg_output) {
+ if (is_dir(arg_output, true) > 0) {
+ log_error("For SplitMode=none, output must be a file.");
+ return -EINVAL;
+ }
+ if (!endswith(arg_output, ".journal")) {
+ log_error("For SplitMode=none, output file name must end with .journal.");
+ return -EINVAL;
+ }
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
@@ -1564,7 +1591,7 @@ int main(int argc, char **argv) {
log_debug("Watchdog is %sd.", enable_disable(r > 0));
log_debug("%s running as pid "PID_FMT,
- program_invocation_short_name, getpid());
+ program_invocation_short_name, getpid_cached());
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index e0858dda7b..ea264989ab 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -811,7 +811,7 @@ int main(int argc, char **argv) {
goto cleanup;
log_debug("%s running as pid "PID_FMT,
- program_invocation_short_name, getpid());
+ program_invocation_short_name, getpid_cached());
use_journal = optind >= argc;
if (use_journal) {
diff --git a/src/journal-remote/meson.build b/src/journal-remote/meson.build
index d266b34e65..ed963d7930 100644
--- a/src/journal-remote/meson.build
+++ b/src/journal-remote/meson.build
@@ -21,7 +21,7 @@ systemd_journal_gatewayd_sources = files('''
microhttpd-util.c
'''.split())
-if conf.get('ENABLE_REMOTE', false) and conf.get('HAVE_LIBCURL', false)
+if conf.get('ENABLE_REMOTE') ==1 and conf.get('HAVE_LIBCURL') == 1
journal_upload_conf = configure_file(
input : 'journal-upload.conf.in',
output : 'journal-upload.conf',
@@ -30,7 +30,7 @@ if conf.get('ENABLE_REMOTE', false) and conf.get('HAVE_LIBCURL', false)
install_dir : pkgsysconfdir)
endif
-if conf.get('ENABLE_REMOTE', false) and conf.get('HAVE_MICROHTTPD', false)
+if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1
journal_remote_conf = configure_file(
input : 'journal-remote.conf.in',
output : 'journal-remote.conf',
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index f5d2d7967a..75c14ec996 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -22,7 +22,7 @@
#include <stdio.h>
#include <string.h>
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#endif
@@ -115,7 +115,7 @@ int mhd_respondf(struct MHD_Connection *connection,
return mhd_respond_internal(connection, code, m, r, MHD_RESPMEM_MUST_FREE);
}
-#ifdef HAVE_GNUTLS
+#if HAVE_GNUTLS
static struct {
const char *const names[4];
diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h
index 7f88c2cb7d..4b2e9da30b 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/journal-remote/microhttpd-util.h
@@ -24,12 +24,10 @@
#include "macro.h"
-/* Those defines are added when options are renamed, hence the check for the *old* name. */
-
-/* Compatiblity with libmicrohttpd < 0.9.38 */
-#ifndef MHD_HTTP_NOT_ACCEPTABLE
-# define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE
-#endif
+/* Those defines are added when options are renamed. If the old names
+ * are not '#define'd, then they are not deprecated yet and there are
+ * enum elements with the same name. Hence let's check for the *old* name,
+ * and define the new name by the value of the old name. */
/* Renamed in µhttpd 0.9.51 */
#ifndef MHD_USE_PIPE_FOR_SHUTDOWN
@@ -41,8 +39,23 @@
# define MHD_USE_EPOLL MHD_USE_EPOLL_LINUX_ONLY
#endif
+/* Renamed in µhttpd 0.9.52 */
+#ifndef MHD_USE_SSL
+# define MHD_USE_TLS MHD_USE_SSL
+#endif
+
+/* Renamed in µhttpd 0.9.53 */
+#ifndef MHD_USE_POLL_INTERNALLY
+# define MHD_USE_POLL_INTERNAL_THREAD MHD_USE_POLL_INTERNALLY
+#endif
+
/* Both the old and new names are defines, check for the new one. */
+/* Compatiblity with libmicrohttpd < 0.9.38 */
+#ifndef MHD_HTTP_NOT_ACCEPTABLE
+# define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE
+#endif
+
/* Renamed in µhttpd 0.9.53 */
#ifndef MHD_HTTP_PAYLOAD_TOO_LARGE
# define MHD_HTTP_PAYLOAD_TOO_LARGE MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
diff --git a/src/journal/.gitignore b/src/journal/.gitignore
deleted file mode 100644
index b93a9462fa..0000000000
--- a/src/journal/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/journald-gperf.c
-/audit_type-list.txt
-/audit_type-*-name.*
diff --git a/src/journal/Makefile b/src/journal/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/journal/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/journal/audit-type.c b/src/journal/audit-type.c
index 71e8790ca8..373d3455ae 100644
--- a/src/journal/audit-type.c
+++ b/src/journal/audit-type.c
@@ -19,7 +19,7 @@
#include <stdio.h>
#include <linux/audit.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
# include <libaudit.h>
#endif
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index 886f6efd8b..bf92da9f90 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -216,7 +216,7 @@ int catalog_file_lang(const char* filename, char **lang) {
return 0;
beg = end - 1;
- while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32)
+ while (beg > filename && !IN_SET(*beg, '.', '/') && end - beg < 32)
beg--;
if (*beg != '.' || end <= beg + 1)
@@ -312,7 +312,7 @@ int catalog_import_file(Hashmap *h, const char *path) {
line[0] == '-' &&
line[1] == '-' &&
line[2] == ' ' &&
- (line[2+1+32] == ' ' || line[2+1+32] == '\0')) {
+ IN_SET(line[2+1+32], ' ', '\0')) {
bool with_language;
sd_id128_t jd;
@@ -479,7 +479,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
goto finish;
}
- r = conf_files_list_strv(&files, ".catalog", root, dirs);
+ r = conf_files_list_strv(&files, ".catalog", root, 0, dirs);
if (r < 0) {
log_error_errno(r, "Failed to get catalog files: %m");
goto finish;
diff --git a/src/journal/compress.c b/src/journal/compress.c
index 818a720ba8..834859b23c 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -23,11 +23,11 @@
#include <sys/mman.h>
#include <unistd.h>
-#ifdef HAVE_XZ
+#if HAVE_XZ
#include <lzma.h>
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
#include <lz4.h>
#include <lz4frame.h>
#endif
@@ -43,7 +43,7 @@
#include "string-util.h"
#include "util.h"
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext);
DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
#endif
@@ -59,7 +59,7 @@ DEFINE_STRING_TABLE_LOOKUP(object_compressed, int);
int compress_blob_xz(const void *src, uint64_t src_size,
void *dst, size_t dst_alloc_size, size_t *dst_size) {
-#ifdef HAVE_XZ
+#if HAVE_XZ
static const lzma_options_lzma opt = {
1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4
@@ -97,7 +97,7 @@ int compress_blob_xz(const void *src, uint64_t src_size,
int compress_blob_lz4(const void *src, uint64_t src_size,
void *dst, size_t dst_alloc_size, size_t *dst_size) {
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
int r;
assert(src);
@@ -133,7 +133,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
int decompress_blob_xz(const void *src, uint64_t src_size,
void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
-#ifdef HAVE_XZ
+#if HAVE_XZ
_cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
lzma_ret ret;
size_t space;
@@ -193,7 +193,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size,
int decompress_blob_lz4(const void *src, uint64_t src_size,
void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max) {
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
char* out;
int r, size; /* LZ4 uses int for size */
@@ -249,7 +249,7 @@ int decompress_startswith_xz(const void *src, uint64_t src_size,
const void *prefix, size_t prefix_len,
uint8_t extra) {
-#ifdef HAVE_XZ
+#if HAVE_XZ
_cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
lzma_ret ret;
@@ -280,7 +280,7 @@ int decompress_startswith_xz(const void *src, uint64_t src_size,
for (;;) {
ret = lzma_code(&s, LZMA_FINISH);
- if (ret != LZMA_STREAM_END && ret != LZMA_OK)
+ if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
return -EBADMSG;
if (*buffer_size - s.avail_out >= prefix_len + 1)
@@ -307,7 +307,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
void **buffer, size_t *buffer_size,
const void *prefix, size_t prefix_len,
uint8_t extra) {
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
/* Checks whether the decompressed blob starts with the
* mentioned prefix. The byte extra needs to follow the
* prefix */
@@ -372,7 +372,7 @@ int decompress_startswith(int compression,
}
int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
-#ifdef HAVE_XZ
+#if HAVE_XZ
_cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
lzma_ret ret;
uint8_t buf[BUFSIZ], out[BUFSIZ];
@@ -417,7 +417,7 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
}
ret = lzma_code(&s, action);
- if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
+ if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END)) {
log_error("Compression failed: code %u", ret);
return -EBADMSG;
}
@@ -449,7 +449,7 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
LZ4F_errorCode_t c;
_cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
_cleanup_free_ char *buf = NULL;
@@ -542,7 +542,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
-#ifdef HAVE_XZ
+#if HAVE_XZ
_cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
lzma_ret ret;
@@ -579,7 +579,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
}
ret = lzma_code(&s, action);
- if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
+ if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END)) {
log_debug("Decompression failed: code %u", ret);
return -EBADMSG;
}
@@ -616,7 +616,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
}
int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
size_t c;
_cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
_cleanup_free_ char *buf = NULL;
diff --git a/src/journal/compress.h b/src/journal/compress.h
index c138099d9a..fb71662a99 100644
--- a/src/journal/compress.h
+++ b/src/journal/compress.h
@@ -34,7 +34,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
static inline int compress_blob(const void *src, uint64_t src_size,
void *dst, size_t dst_alloc_size, size_t *dst_size) {
int r;
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
r = compress_blob_lz4(src, src_size, dst, dst_alloc_size, dst_size);
if (r == 0)
return OBJECT_COMPRESSED_LZ4;
@@ -74,7 +74,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes);
int decompress_stream_xz(int fdf, int fdt, uint64_t max_size);
int decompress_stream_lz4(int fdf, int fdt, uint64_t max_size);
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
# define compress_stream compress_stream_lz4
# define COMPRESSED_EXT ".lz4"
#else
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 67edb43960..1bd5de4c43 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -162,11 +162,11 @@ enum {
#define HEADER_INCOMPATIBLE_ANY (HEADER_INCOMPATIBLE_COMPRESSED_XZ|HEADER_INCOMPATIBLE_COMPRESSED_LZ4)
-#if defined(HAVE_XZ) && defined(HAVE_LZ4)
+#if HAVE_XZ && HAVE_LZ4
# define HEADER_INCOMPATIBLE_SUPPORTED HEADER_INCOMPATIBLE_ANY
-#elif defined(HAVE_XZ)
+#elif HAVE_XZ
# define HEADER_INCOMPATIBLE_SUPPORTED HEADER_INCOMPATIBLE_COMPRESSED_XZ
-#elif defined(HAVE_LZ4)
+#elif HAVE_LZ4
# define HEADER_INCOMPATIBLE_SUPPORTED HEADER_INCOMPATIBLE_COMPRESSED_LZ4
#else
# define HEADER_INCOMPATIBLE_SUPPORTED 0
@@ -177,7 +177,7 @@ enum {
};
#define HEADER_COMPATIBLE_ANY HEADER_COMPATIBLE_SEALED
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
# define HEADER_COMPATIBLE_SUPPORTED HEADER_COMPATIBLE_SEALED
#else
# define HEADER_COMPATIBLE_SUPPORTED 0
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 4ff38de2e6..3027801ab1 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -322,8 +322,7 @@ bool journal_file_is_offlining(JournalFile *f) {
__sync_synchronize();
- if (f->offline_state == OFFLINE_DONE ||
- f->offline_state == OFFLINE_JOINED)
+ if (IN_SET(f->offline_state, OFFLINE_DONE, OFFLINE_JOINED))
return false;
return true;
@@ -332,7 +331,7 @@ bool journal_file_is_offlining(JournalFile *f) {
JournalFile* journal_file_close(JournalFile *f) {
assert(f);
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
/* Write the final tag */
if (f->seal && f->writable) {
int r;
@@ -379,11 +378,11 @@ JournalFile* journal_file_close(JournalFile *f) {
ordered_hashmap_free_free(f->chain_cache);
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
free(f->compress_buffer);
#endif
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
if (f->fss_file)
munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size));
else
@@ -727,7 +726,7 @@ static unsigned type_to_context(ObjectType type) {
return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0;
}
-static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
+static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret, size_t *ret_size) {
int r;
assert(f);
@@ -749,7 +748,7 @@ static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_alway
return -EADDRNOTAVAIL;
}
- return mmap_cache_get(f->mmap, f->cache_fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret);
+ return mmap_cache_get(f->mmap, f->cache_fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret, ret_size);
}
static uint64_t minimum_header_size(Object *o) {
@@ -770,9 +769,173 @@ static uint64_t minimum_header_size(Object *o) {
return table[o->object.type];
}
+/* Lightweight object checks. We want this to be fast, so that we won't
+ * slowdown every journal_file_move_to_object() call too much. */
+static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o) {
+ assert(f);
+ assert(o);
+
+ switch (o->object.type) {
+
+ case OBJECT_DATA: {
+ if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
+ log_debug("Bad n_entries: %"PRIu64": %"PRIu64,
+ le64toh(o->data.n_entries), offset);
+ return -EBADMSG;
+ }
+
+ if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) {
+ log_debug("Bad object size (<= %zu): %"PRIu64": %"PRIu64,
+ offsetof(DataObject, payload),
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID64(le64toh(o->data.next_hash_offset)) ||
+ !VALID64(le64toh(o->data.next_field_offset)) ||
+ !VALID64(le64toh(o->data.entry_offset)) ||
+ !VALID64(le64toh(o->data.entry_array_offset))) {
+ log_debug("Invalid offset, next_hash_offset="OFSfmt", next_field_offset="OFSfmt
+ ", entry_offset="OFSfmt", entry_array_offset="OFSfmt": %"PRIu64,
+ le64toh(o->data.next_hash_offset),
+ le64toh(o->data.next_field_offset),
+ le64toh(o->data.entry_offset),
+ le64toh(o->data.entry_array_offset),
+ offset);
+ return -EBADMSG;
+ }
+
+ break;
+ }
+
+ case OBJECT_FIELD:
+ if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) {
+ log_debug(
+ "Bad field size (<= %zu): %"PRIu64": %"PRIu64,
+ offsetof(FieldObject, payload),
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID64(le64toh(o->field.next_hash_offset)) ||
+ !VALID64(le64toh(o->field.head_data_offset))) {
+ log_debug(
+ "Invalid offset, next_hash_offset="OFSfmt
+ ", head_data_offset="OFSfmt": %"PRIu64,
+ le64toh(o->field.next_hash_offset),
+ le64toh(o->field.head_data_offset),
+ offset);
+ return -EBADMSG;
+ }
+ break;
+
+ case OBJECT_ENTRY:
+ if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) {
+ log_debug(
+ "Bad entry size (<= %zu): %"PRIu64": %"PRIu64,
+ offsetof(EntryObject, items),
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) {
+ log_debug(
+ "Invalid number items in entry: %"PRIu64": %"PRIu64,
+ (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (le64toh(o->entry.seqnum) <= 0) {
+ log_debug(
+ "Invalid entry seqnum: %"PRIx64": %"PRIu64,
+ le64toh(o->entry.seqnum),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID_REALTIME(le64toh(o->entry.realtime))) {
+ log_debug(
+ "Invalid entry realtime timestamp: %"PRIu64": %"PRIu64,
+ le64toh(o->entry.realtime),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) {
+ log_debug(
+ "Invalid entry monotonic timestamp: %"PRIu64": %"PRIu64,
+ le64toh(o->entry.monotonic),
+ offset);
+ return -EBADMSG;
+ }
+
+ break;
+
+ case OBJECT_DATA_HASH_TABLE:
+ case OBJECT_FIELD_HASH_TABLE:
+ if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 ||
+ (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) {
+ log_debug(
+ "Invalid %s hash table size: %"PRIu64": %"PRIu64,
+ o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field",
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ break;
+
+ case OBJECT_ENTRY_ARRAY:
+ if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 ||
+ (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) {
+ log_debug(
+ "Invalid object entry array size: %"PRIu64": %"PRIu64,
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) {
+ log_debug(
+ "Invalid object entry array next_entry_array_offset: "OFSfmt": %"PRIu64,
+ le64toh(o->entry_array.next_entry_array_offset),
+ offset);
+ return -EBADMSG;
+ }
+
+ break;
+
+ case OBJECT_TAG:
+ if (le64toh(o->object.size) != sizeof(TagObject)) {
+ log_debug(
+ "Invalid object tag size: %"PRIu64": %"PRIu64,
+ le64toh(o->object.size),
+ offset);
+ return -EBADMSG;
+ }
+
+ if (!VALID_EPOCH(le64toh(o->tag.epoch))) {
+ log_debug(
+ "Invalid object tag epoch: %"PRIu64": %"PRIu64,
+ le64toh(o->tag.epoch),
+ offset);
+ return -EBADMSG;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) {
int r;
void *t;
+ size_t tsize;
Object *o;
uint64_t s;
@@ -791,7 +954,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
return -EBADMSG;
}
- r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t);
+ r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t, &tsize);
if (r < 0)
return r;
@@ -822,14 +985,18 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
return -EBADMSG;
}
- if (s > sizeof(ObjectHeader)) {
- r = journal_file_move_to(f, type, false, offset, s, &t);
+ if (s > tsize) {
+ r = journal_file_move_to(f, type, false, offset, s, &t, NULL);
if (r < 0)
return r;
o = (Object*) t;
}
+ r = journal_file_check_object(f, offset, o);
+ if (r < 0)
+ return r;
+
*ret = o;
return 0;
}
@@ -893,7 +1060,7 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O
if (r < 0)
return r;
- r = journal_file_move_to(f, type, false, p, size, &t);
+ r = journal_file_move_to(f, type, false, p, size, &t, NULL);
if (r < 0)
return r;
@@ -991,7 +1158,7 @@ int journal_file_map_data_hash_table(JournalFile *f) {
OBJECT_DATA_HASH_TABLE,
true,
p, s,
- &t);
+ &t, NULL);
if (r < 0)
return r;
@@ -1017,7 +1184,7 @@ int journal_file_map_field_hash_table(JournalFile *f) {
OBJECT_FIELD_HASH_TABLE,
true,
p, s,
- &t);
+ &t, NULL);
if (r < 0)
return r;
@@ -1234,7 +1401,7 @@ int journal_file_find_data_object_with_hash(
goto next;
if (o->object.flags & OBJECT_COMPRESSION_MASK) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
uint64_t l;
size_t rsize = 0;
@@ -1346,7 +1513,7 @@ static int journal_file_append_field(
if (r < 0)
return r;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_FIELD, o, p);
if (r < 0)
return r;
@@ -1398,7 +1565,7 @@ static int journal_file_append_data(
o->data.hash = htole64(hash);
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) {
size_t rsize = 0;
@@ -1423,7 +1590,7 @@ static int journal_file_append_data(
if (r < 0)
return r;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p);
if (r < 0)
return r;
@@ -1483,8 +1650,7 @@ uint64_t journal_file_entry_array_n_items(Object *o) {
uint64_t journal_file_hash_table_n_items(Object *o) {
assert(o);
- if (o->object.type != OBJECT_DATA_HASH_TABLE &&
- o->object.type != OBJECT_FIELD_HASH_TABLE)
+ if (!IN_SET(o->object.type, OBJECT_DATA_HASH_TABLE, OBJECT_FIELD_HASH_TABLE))
return 0;
return (le64toh(o->object.size) - offsetof(Object, hash_table.items)) / sizeof(HashItem);
@@ -1538,7 +1704,7 @@ static int link_entry_into_array(JournalFile *f,
if (r < 0)
return r;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, o, q);
if (r < 0)
return r;
@@ -1688,7 +1854,7 @@ static int journal_file_append_entry_internal(
o->entry.xor_hash = htole64(xor_hash);
o->entry.boot_id = f->header->boot_id;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np);
if (r < 0)
return r;
@@ -1824,7 +1990,7 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st
ts = &_ts;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_maybe_append_tag(f, ts->realtime);
if (r < 0)
return r;
@@ -3074,8 +3240,7 @@ int journal_file_open(
assert(ret);
assert(fd >= 0 || fname);
- if ((flags & O_ACCMODE) != O_RDONLY &&
- (flags & O_ACCMODE) != O_RDWR)
+ if (!IN_SET((flags & O_ACCMODE), O_RDONLY, O_RDWR))
return -EINVAL;
if (fname) {
@@ -3094,12 +3259,12 @@ int journal_file_open(
f->flags = flags;
f->prot = prot_from_flags(flags);
f->writable = (flags & O_ACCMODE) != O_RDONLY;
-#if defined(HAVE_LZ4)
+#if HAVE_LZ4
f->compress_lz4 = compress;
-#elif defined(HAVE_XZ)
+#elif HAVE_XZ
f->compress_xz = compress;
#endif
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
f->seal = seal;
#endif
@@ -3170,7 +3335,7 @@ int journal_file_open(
fd_setcrtime(f->fd, 0);
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
/* Try to load the FSPRG state, and if we can't, then
* just don't do sealing */
if (f->seal) {
@@ -3196,7 +3361,7 @@ int journal_file_open(
goto fail;
}
- r = mmap_cache_get(f->mmap, f->cache_fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h);
+ r = mmap_cache_get(f->mmap, f->cache_fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h, NULL);
if (r < 0)
goto fail;
@@ -3211,7 +3376,7 @@ int journal_file_open(
goto fail;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
if (!newly_created && f->writable) {
r = journal_file_fss_load(f);
if (r < 0)
@@ -3231,7 +3396,7 @@ int journal_file_open(
goto fail;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_hmac_setup(f);
if (r < 0)
goto fail;
@@ -3246,7 +3411,7 @@ int journal_file_open(
if (r < 0)
goto fail;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_append_first_tag(f);
if (r < 0)
goto fail;
@@ -3457,7 +3622,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
return -E2BIG;
if (o->object.flags & OBJECT_COMPRESSION_MASK) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
size_t rsize = 0;
r = decompress_blob(o->object.flags & OBJECT_COMPRESSION_MASK,
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index df457c9a81..008dba604b 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -21,7 +21,7 @@
#include <inttypes.h>
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#include <gcrypt.h>
#endif
@@ -121,12 +121,12 @@ typedef struct JournalFile {
pthread_t offline_thread;
volatile OfflineState offline_state;
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
void *compress_buffer;
size_t compress_buffer_size;
#endif
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
gcry_md_hd_t hmac;
bool hmac_running;
diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c
index 5ee10498d1..4e194bd809 100644
--- a/src/journal/journal-qrcode.c
+++ b/src/journal/journal-qrcode.c
@@ -65,11 +65,11 @@ int print_qr_code(
if (!f)
return -ENOMEM;
- fputs("fss://", f);
+ fputs_unlocked("fss://", f);
for (i = 0; i < seed_size; i++) {
if (i > 0 && i % 3 == 0)
- fputc('-', f);
+ fputc_unlocked('-', f);
fprintf(f, "%02x", ((uint8_t*) seed)[i]);
}
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index 440fba67ca..4acef26394 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -114,9 +114,8 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
if (isempty(buffer+8))
return 0;
- zero(iov);
- IOVEC_SET_STRING(iov[0], buffer);
- IOVEC_SET_STRING(iov[1], p);
+ iov[0] = IOVEC_MAKE_STRING(buffer);
+ iov[1] = IOVEC_MAKE_STRING(p);
return sd_journal_sendv(iov, 2);
}
@@ -167,7 +166,7 @@ _printf_(1, 0) static int fill_iovec_sprintf(const char *format, va_list ap, int
(void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */
- IOVEC_SET_STRING(iov[i++], buffer);
+ iov[i++] = IOVEC_MAKE_STRING(buffer);
format = va_arg(ap, char *);
}
@@ -259,27 +258,19 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
* newline, then the size (64bit LE), followed
* by the data and a final newline */
- w[j].iov_base = iov[i].iov_base;
- w[j].iov_len = c - (char*) iov[i].iov_base;
- j++;
-
- IOVEC_SET_STRING(w[j++], "\n");
+ w[j++] = IOVEC_MAKE(iov[i].iov_base, c - (char*) iov[i].iov_base);
+ w[j++] = IOVEC_MAKE_STRING("\n");
l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
- w[j].iov_base = &l[i];
- w[j].iov_len = sizeof(uint64_t);
- j++;
-
- w[j].iov_base = c + 1;
- w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1;
- j++;
+ w[j++] = IOVEC_MAKE(&l[i], sizeof(uint64_t));
+ w[j++] = IOVEC_MAKE(c + 1, iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1);
} else
/* Nothing special? Then just add the line and
* append a newline */
w[j++] = iov[i];
- IOVEC_SET_STRING(w[j++], "\n");
+ w[j++] = IOVEC_MAKE_STRING("\n");
}
if (!have_syslog_identifier &&
@@ -291,9 +282,9 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
* since everything else is much nicer to retrieve
* from the outside. */
- IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER=");
- IOVEC_SET_STRING(w[j++], program_invocation_short_name);
- IOVEC_SET_STRING(w[j++], "\n");
+ w[j++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=");
+ w[j++] = IOVEC_MAKE_STRING(program_invocation_short_name);
+ w[j++] = IOVEC_MAKE_STRING("\n");
}
fd = journal_fd();
@@ -311,7 +302,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
if (errno == ENOENT)
return 0;
- if (errno != EMSGSIZE && errno != ENOBUFS)
+ if (!IN_SET(errno, EMSGSIZE, ENOBUFS))
return -errno;
/* Message doesn't fit... Let's dump the data in a memfd or
@@ -380,9 +371,9 @@ static int fill_iovec_perror_and_send(const char *message, int skip, struct iove
xsprintf(error, "ERRNO=%i", _saved_errno_);
assert_cc(3 == LOG_ERR);
- IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3");
- IOVEC_SET_STRING(iov[skip+1], buffer);
- IOVEC_SET_STRING(iov[skip+2], error);
+ iov[skip+0] = IOVEC_MAKE_STRING("PRIORITY=3");
+ iov[skip+1] = IOVEC_MAKE_STRING(buffer);
+ iov[skip+2] = IOVEC_MAKE_STRING(error);
return sd_journal_sendv(iov, skip + 3);
}
@@ -492,20 +483,19 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con
* CODE_FUNC=, hence let's do it manually here. */
ALLOCA_CODE_FUNC(f, func);
- zero(iov);
- IOVEC_SET_STRING(iov[0], buffer);
- IOVEC_SET_STRING(iov[1], p);
- IOVEC_SET_STRING(iov[2], file);
- IOVEC_SET_STRING(iov[3], line);
- IOVEC_SET_STRING(iov[4], f);
+ iov[0] = IOVEC_MAKE_STRING(buffer);
+ iov[1] = IOVEC_MAKE_STRING(p);
+ iov[2] = IOVEC_MAKE_STRING(file);
+ iov[3] = IOVEC_MAKE_STRING(line);
+ iov[4] = IOVEC_MAKE_STRING(f);
return sd_journal_sendv(iov, ELEMENTSOF(iov));
}
_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) {
+ _cleanup_free_ struct iovec *iov = NULL;
int r, i, j;
va_list ap;
- struct iovec *iov = NULL;
char *f;
va_start(ap, format);
@@ -519,9 +509,9 @@ _public_ int sd_journal_send_with_location(const char *file, const char *line, c
ALLOCA_CODE_FUNC(f, func);
- IOVEC_SET_STRING(iov[0], file);
- IOVEC_SET_STRING(iov[1], line);
- IOVEC_SET_STRING(iov[2], f);
+ iov[0] = IOVEC_MAKE_STRING(file);
+ iov[1] = IOVEC_MAKE_STRING(line);
+ iov[2] = IOVEC_MAKE_STRING(f);
r = sd_journal_sendv(iov, i);
@@ -529,8 +519,6 @@ finish:
for (j = 3; j < i; j++)
free(iov[j].iov_base);
- free(iov);
-
return r;
}
@@ -550,9 +538,9 @@ _public_ int sd_journal_sendv_with_location(
ALLOCA_CODE_FUNC(f, func);
- IOVEC_SET_STRING(niov[n++], file);
- IOVEC_SET_STRING(niov[n++], line);
- IOVEC_SET_STRING(niov[n++], f);
+ niov[n++] = IOVEC_MAKE_STRING(file);
+ niov[n++] = IOVEC_MAKE_STRING(line);
+ niov[n++] = IOVEC_MAKE_STRING(f);
return sd_journal_sendv(niov, n);
}
@@ -567,9 +555,9 @@ _public_ int sd_journal_perror_with_location(
ALLOCA_CODE_FUNC(f, func);
- IOVEC_SET_STRING(iov[0], file);
- IOVEC_SET_STRING(iov[1], line);
- IOVEC_SET_STRING(iov[2], f);
+ iov[0] = IOVEC_MAKE_STRING(file);
+ iov[1] = IOVEC_MAKE_STRING(line);
+ iov[2] = IOVEC_MAKE_STRING(f);
return fill_iovec_perror_and_send(message, 3, iov);
}
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 9feb5b5ae6..e756f51d0f 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -150,7 +150,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
warning(offset, "Unused data (entry_offset==0)");
if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
- error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries);
+ error(offset, "Bad n_entries: %"PRIu64, le64toh(o->data.n_entries));
return -EBADMSG;
}
@@ -187,15 +187,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
return -EBADMSG;
}
- if (!VALID64(o->data.next_hash_offset) ||
- !VALID64(o->data.next_field_offset) ||
- !VALID64(o->data.entry_offset) ||
- !VALID64(o->data.entry_array_offset)) {
+ if (!VALID64(le64toh(o->data.next_hash_offset)) ||
+ !VALID64(le64toh(o->data.next_field_offset)) ||
+ !VALID64(le64toh(o->data.entry_offset)) ||
+ !VALID64(le64toh(o->data.entry_array_offset))) {
error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
- o->data.next_hash_offset,
- o->data.next_field_offset,
- o->data.entry_offset,
- o->data.entry_array_offset);
+ le64toh(o->data.next_hash_offset),
+ le64toh(o->data.next_field_offset),
+ le64toh(o->data.entry_offset),
+ le64toh(o->data.entry_array_offset));
return -EBADMSG;
}
@@ -211,12 +211,12 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
return -EBADMSG;
}
- if (!VALID64(o->field.next_hash_offset) ||
- !VALID64(o->field.head_data_offset)) {
+ if (!VALID64(le64toh(o->field.next_hash_offset)) ||
+ !VALID64(le64toh(o->field.head_data_offset))) {
error(offset,
"Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
- o->field.next_hash_offset,
- o->field.head_data_offset);
+ le64toh(o->field.next_hash_offset),
+ le64toh(o->field.head_data_offset));
return -EBADMSG;
}
break;
@@ -259,12 +259,12 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
}
for (i = 0; i < journal_file_entry_n_items(o); i++) {
- if (o->entry.items[i].object_offset == 0 ||
- !VALID64(o->entry.items[i].object_offset)) {
+ if (le64toh(o->entry.items[i].object_offset) == 0 ||
+ !VALID64(le64toh(o->entry.items[i].object_offset))) {
error(offset,
"Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
i, journal_file_entry_n_items(o),
- o->entry.items[i].object_offset);
+ le64toh(o->entry.items[i].object_offset));
return -EBADMSG;
}
}
@@ -325,10 +325,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
return -EBADMSG;
}
- if (!VALID64(o->entry_array.next_entry_array_offset)) {
+ if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) {
error(offset,
"Invalid object entry array next_entry_array_offset: "OFSfmt,
- o->entry_array.next_entry_array_offset);
+ le64toh(o->entry_array.next_entry_array_offset));
return -EBADMSG;
}
@@ -352,10 +352,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
return -EBADMSG;
}
- if (!VALID_EPOCH(o->tag.epoch)) {
+ if (!VALID_EPOCH(le64toh(o->tag.epoch))) {
error(offset,
"Invalid object tag epoch: %"PRIu64,
- o->tag.epoch);
+ le64toh(o->tag.epoch));
return -EBADMSG;
}
@@ -392,7 +392,7 @@ static int contains_uint64(MMapCache *m, MMapFileDescriptor *f, uint64_t n, uint
c = (a + b) / 2;
- r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
+ r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
if (r < 0)
return r;
@@ -834,13 +834,13 @@ int journal_file_verify(
bool found_last = false;
const char *tmp_dir = NULL;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
uint64_t last_tag = 0;
#endif
assert(f);
if (key) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
r = journal_file_parse_verification_key(f, key);
if (r < 0) {
log_error("Failed to parse seed.");
@@ -1103,13 +1103,13 @@ int journal_file_verify(
goto fail;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
if (f->seal) {
uint64_t q, rt;
debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
- rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
+ rt = f->fss_start_usec + le64toh(o->tag.epoch) * f->fss_interval_usec;
if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
error(p, "tag/entry realtime timestamp out of synchronization");
r = -EBADMSG;
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 2313c8c678..e826fa631e 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -105,7 +105,7 @@ static char **arg_file = NULL;
static bool arg_file_stdin = false;
static int arg_priorities = 0xFF;
static char *arg_verify_key = NULL;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
static bool arg_force = false;
#endif
@@ -248,7 +248,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
if (r >= 0)
x += 32;
- if (*x != '-' && *x != '+' && *x != 0)
+ if (!IN_SET(*x, 0, '-', '+'))
return -EINVAL;
if (*x != 0) {
@@ -313,7 +313,7 @@ static void help(void) {
" -D --directory=PATH Show journal files from directory\n"
" --file=PATH Show journal file\n"
" --root=ROOT Operate on files below a root directory\n"
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
" --interval=TIME Time interval for changing the FSS sealing key\n"
" --verify-key=KEY Specify FSS verification key\n"
" --force Override of the FSS key pair with --setup-keys\n"
@@ -336,7 +336,7 @@ static void help(void) {
" --dump-catalog Show entries in the message catalog\n"
" --update-catalog Update the message catalog database\n"
" --new-id128 Generate a new 128-bit ID\n"
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
" --setup-keys Generate a new FSS key pair\n"
#endif
, program_invocation_short_name);
@@ -477,11 +477,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_output == OUTPUT_EXPORT ||
- arg_output == OUTPUT_JSON ||
- arg_output == OUTPUT_JSON_PRETTY ||
- arg_output == OUTPUT_JSON_SSE ||
- arg_output == OUTPUT_CAT)
+ if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_CAT))
arg_quiet = true;
break;
@@ -673,7 +669,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_VACUUM;
break;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
case ARG_FORCE:
arg_force = true;
break;
@@ -1565,7 +1561,7 @@ static int add_syslog_identifier(sd_journal *j) {
}
static int setup_keys(void) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
size_t mpk_size, seed_size, state_size, i;
uint8_t *mpk, *seed, *state;
int fd = -1, r;
@@ -1576,7 +1572,7 @@ static int setup_keys(void) {
struct stat st;
r = stat("/var/log/journal", &st);
- if (r < 0 && errno != ENOENT && errno != ENOTDIR)
+ if (r < 0 && !IN_SET(errno, ENOENT, ENOTDIR))
return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
if (r < 0 || !S_ISDIR(st.st_mode)) {
@@ -1731,7 +1727,7 @@ static int setup_keys(void) {
} else
fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
-#ifdef HAVE_QRENCODE
+#if HAVE_QRENCODE
/* If this is not an UTF-8 system don't print any QR codes */
if (is_locale_utf8()) {
fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
@@ -1773,7 +1769,7 @@ static int verify(sd_journal *j) {
int k;
usec_t first = 0, validated = 0, last = 0;
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
#endif
@@ -2170,7 +2166,7 @@ int main(int argc, char *argv[]) {
if (d->is_root)
continue;
- q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true);
+ q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, !arg_quiet);
if (q < 0) {
log_error_errno(q, "Failed to vacuum %s: %m", d->path);
r = q;
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
index a433c91c54..3334418f33 100644
--- a/src/journal/journald-audit.c
+++ b/src/journal/journald-audit.c
@@ -49,7 +49,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io
return -ENOMEM;
memcpy(c, field, l);
- for (e = *p; *e != ' ' && *e != 0; e++) {
+ for (e = *p; !IN_SET(*e, 0, ' '); e++) {
if (!GREEDY_REALLOC(c, allocated, l+2))
return -ENOMEM;
@@ -110,7 +110,7 @@ static int map_string_field_internal(const char *field, const char **p, struct i
return -ENOMEM;
memcpy(c, field, l);
- for (e = *p; *e != ' ' && *e != 0; e += 2) {
+ for (e = *p; !IN_SET(*e, 0, ' '); e += 2) {
int a, b;
uint8_t x;
@@ -167,7 +167,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec **
for (e = *p; e < *p + 16; e++) {
- if (*e == 0 || *e == ' ')
+ if (IN_SET(*e, 0, ' '))
return 0;
if (*e == '=')
@@ -176,7 +176,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec **
if (!((*e >= 'a' && *e <= 'z') ||
(*e >= 'A' && *e <= 'Z') ||
(*e >= '0' && *e <= '9') ||
- *e == '_' || *e == '-'))
+ IN_SET(*e, '_', '-')))
return 0;
}
@@ -383,26 +383,26 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
return;
}
- IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
+ iov[n_iov++] = IOVEC_MAKE_STRING("_TRANSPORT=audit");
sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
(usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
- IOVEC_SET_STRING(iov[n_iov++], source_time_field);
+ iov[n_iov++] = IOVEC_MAKE_STRING(source_time_field);
sprintf(type_field, "_AUDIT_TYPE=%i", type);
- IOVEC_SET_STRING(iov[n_iov++], type_field);
+ iov[n_iov++] = IOVEC_MAKE_STRING(type_field);
sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
- IOVEC_SET_STRING(iov[n_iov++], id_field);
+ iov[n_iov++] = IOVEC_MAKE_STRING(id_field);
assert_cc(4 == LOG_FAC(LOG_AUTH));
- IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=4");
- IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit");
+ iov[n_iov++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=4");
+ iov[n_iov++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=audit");
type_name = audit_type_name_alloca(type);
m = strjoina("MESSAGE=", type_name, " ", p);
- IOVEC_SET_STRING(iov[n_iov++], m);
+ iov[n_iov++] = IOVEC_MAKE_STRING(m);
z = n_iov;
@@ -413,7 +413,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s
goto finish;
}
- server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
+ server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, LOG_NOTICE, 0);
finish:
/* free() all entries that map_all_fields() added. All others
@@ -528,7 +528,7 @@ int server_open_audit(Server *s) {
s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
if (s->audit_fd < 0) {
- if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
+ if (IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT))
log_debug("Audit not supported in the kernel.");
else
log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c
index 5fbcdb43c2..039f1a68ce 100644
--- a/src/journal/journald-console.c
+++ b/src/journal/journald-console.c
@@ -59,9 +59,10 @@ void server_forward_console(
struct timespec ts;
char tbuf[sizeof("[] ")-1 + DECIMAL_STR_MAX(ts.tv_sec) + DECIMAL_STR_MAX(ts.tv_nsec)-3 + 1];
char header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t)];
- int n = 0, fd;
_cleanup_free_ char *ident_buf = NULL;
+ _cleanup_close_ int fd = -1;
const char *tty;
+ int n = 0;
assert(s);
assert(message);
@@ -75,7 +76,8 @@ void server_forward_console(
xsprintf(tbuf, "[%5"PRI_TIME".%06"PRI_NSEC"] ",
ts.tv_sec,
(nsec_t)ts.tv_nsec / 1000);
- IOVEC_SET_STRING(iovec[n++], tbuf);
+
+ iovec[n++] = IOVEC_MAKE_STRING(tbuf);
}
/* Second: identifier and PID */
@@ -88,19 +90,19 @@ void server_forward_console(
xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
if (identifier)
- IOVEC_SET_STRING(iovec[n++], identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
- IOVEC_SET_STRING(iovec[n++], header_pid);
+ iovec[n++] = IOVEC_MAKE_STRING(header_pid);
} else if (identifier) {
- IOVEC_SET_STRING(iovec[n++], identifier);
- IOVEC_SET_STRING(iovec[n++], ": ");
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(": ");
}
/* Fourth: message */
- IOVEC_SET_STRING(iovec[n++], message);
- IOVEC_SET_STRING(iovec[n++], "\n");
+ iovec[n++] = IOVEC_MAKE_STRING(message);
+ iovec[n++] = IOVEC_MAKE_STRING("\n");
- tty = s->tty_path ? s->tty_path : "/dev/console";
+ tty = s->tty_path ?: "/dev/console";
/* Before you ask: yes, on purpose we open/close the console for each log line we write individually. This is a
* good strategy to avoid journald getting killed by the kernel's SAK concept (it doesn't fix this entirely,
@@ -115,6 +117,4 @@ void server_forward_console(
if (writev(fd, iovec, n) < 0)
log_debug_errno(errno, "Failed to write to %s for logging: %m", tty);
-
- safe_close(fd);
}
diff --git a/src/journal/journald-context.c b/src/journal/journald-context.c
new file mode 100644
index 0000000000..eaa7f2544f
--- /dev/null
+++ b/src/journal/journald-context.c
@@ -0,0 +1,588 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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_SELINUX
+#include <selinux/selinux.h>
+#endif
+
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "cgroup-util.h"
+#include "journald-context.h"
+#include "process-util.h"
+#include "string-util.h"
+#include "user-util.h"
+
+/* This implements a metadata cache for clients, which are identified by their PID. Requesting metadata through /proc
+ * is expensive, hence let's cache the data if we can. Note that this means the metadata might be out-of-date when we
+ * store it, but it might already be anyway, as we request the data asynchronously from /proc at a different time the
+ * log entry was originally created. We hence just increase the "window of inaccuracy" a bit.
+ *
+ * The cache is indexed by the PID. Entries may be "pinned" in the cache, in which case the entries are not removed
+ * until they are unpinned. Unpinned entries are kept around until cache pressure is seen. Cache entries older than 5s
+ * are never used (a sad attempt to deal with the UNIX weakness of PIDs reuse), cache entries older than 1s are
+ * refreshed in an incremental way (meaning: data is reread from /proc, but any old data we can't refresh is not
+ * flushed out). Data newer than 1s is used immediately without refresh.
+ *
+ * Log stream clients (i.e. all clients using the AF_UNIX/SOCK_STREAM stdout/stderr transport) will pin a cache entry
+ * as long as their socket is connected. Note that cache entries are shared between different transports. That means a
+ * cache entry pinned for the stream connection logic may be reused for the syslog or native protocols.
+ *
+ * Caching metadata like this has two major benefits:
+ *
+ * 1. Reading metadata is expensive, and we can thus substantially speed up log processing under flood.
+ *
+ * 2. Because metadata caching is shared between stream and datagram transports and stream connections pin a cache
+ * entry there's a good chance we can properly map a substantial set of datagram log messages to their originating
+ * service, as all services (unless explicitly configured otherwise) will have their stdout/stderr connected to a
+ * stream connection. This should improve cases where a service process logs immediately before exiting and we
+ * previously had trouble associating the log message with the service.
+ *
+ * NB: With and without the metadata cache: the implicitly added entry metadata in the journal (with the exception of
+ * UID/PID/GID and SELinux label) must be understood as possibly slightly out of sync (i.e. sometimes slighly older
+ * and sometimes slightly newer than what was current at the log event).
+ */
+
+/* We refresh every 1s */
+#define REFRESH_USEC (1*USEC_PER_SEC)
+
+/* Data older than 5s we flush out */
+#define MAX_USEC (5*USEC_PER_SEC)
+
+/* Keep at most 16K entries in the cache. (Note though that this limit may be violated if enough streams pin entries in
+ * the cache, in which case we *do* permit this limit to be breached. That's safe however, as the number of stream
+ * clients itself is limited.) */
+#define CACHE_MAX (16*1024)
+
+static int client_context_compare(const void *a, const void *b) {
+ const ClientContext *x = a, *y = b;
+
+ if (x->timestamp < y->timestamp)
+ return -1;
+ if (x->timestamp > y->timestamp)
+ return 1;
+
+ if (x->pid < y->pid)
+ return -1;
+ if (x->pid > y->pid)
+ return 1;
+
+ return 0;
+}
+
+static int client_context_new(Server *s, pid_t pid, ClientContext **ret) {
+ ClientContext *c;
+ int r;
+
+ assert(s);
+ assert(pid_is_valid(pid));
+ assert(ret);
+
+ r = hashmap_ensure_allocated(&s->client_contexts, NULL);
+ if (r < 0)
+ return r;
+
+ r = prioq_ensure_allocated(&s->client_contexts_lru, client_context_compare);
+ if (r < 0)
+ return r;
+
+ c = new0(ClientContext, 1);
+ if (!c)
+ return -ENOMEM;
+
+ c->pid = pid;
+
+ c->uid = UID_INVALID;
+ c->gid = GID_INVALID;
+ c->auditid = AUDIT_SESSION_INVALID;
+ c->loginuid = UID_INVALID;
+ c->owner_uid = UID_INVALID;
+ c->lru_index = PRIOQ_IDX_NULL;
+ c->timestamp = USEC_INFINITY;
+
+ r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c);
+ if (r < 0) {
+ free(c);
+ return r;
+ }
+
+ *ret = c;
+ return 0;
+}
+
+static void client_context_reset(ClientContext *c) {
+ assert(c);
+
+ c->timestamp = USEC_INFINITY;
+
+ c->uid = UID_INVALID;
+ c->gid = GID_INVALID;
+
+ c->comm = mfree(c->comm);
+ c->exe = mfree(c->exe);
+ c->cmdline = mfree(c->cmdline);
+ c->capeff = mfree(c->capeff);
+
+ c->auditid = AUDIT_SESSION_INVALID;
+ c->loginuid = UID_INVALID;
+
+ c->cgroup = mfree(c->cgroup);
+ c->session = mfree(c->session);
+ c->owner_uid = UID_INVALID;
+ c->unit = mfree(c->unit);
+ c->user_unit = mfree(c->user_unit);
+ c->slice = mfree(c->slice);
+ c->user_slice = mfree(c->user_slice);
+
+ c->invocation_id = SD_ID128_NULL;
+
+ c->label = mfree(c->label);
+ c->label_size = 0;
+}
+
+static ClientContext* client_context_free(Server *s, ClientContext *c) {
+ assert(s);
+
+ if (!c)
+ return NULL;
+
+ assert_se(hashmap_remove(s->client_contexts, PID_TO_PTR(c->pid)) == c);
+
+ if (c->in_lru)
+ assert_se(prioq_remove(s->client_contexts_lru, c, &c->lru_index) >= 0);
+
+ client_context_reset(c);
+
+ return mfree(c);
+}
+
+static void client_context_read_uid_gid(ClientContext *c, const struct ucred *ucred) {
+ assert(c);
+ assert(pid_is_valid(c->pid));
+
+ /* The ucred data passed in is always the most current and accurate, if we have any. Use it. */
+ if (ucred && uid_is_valid(ucred->uid))
+ c->uid = ucred->uid;
+ else
+ (void) get_process_uid(c->pid, &c->uid);
+
+ if (ucred && gid_is_valid(ucred->gid))
+ c->gid = ucred->gid;
+ else
+ (void) get_process_gid(c->pid, &c->gid);
+}
+
+static void client_context_read_basic(ClientContext *c) {
+ char *t;
+
+ assert(c);
+ assert(pid_is_valid(c->pid));
+
+ if (get_process_comm(c->pid, &t) >= 0)
+ free_and_replace(c->comm, t);
+
+ if (get_process_exe(c->pid, &t) >= 0)
+ free_and_replace(c->exe, t);
+
+ if (get_process_cmdline(c->pid, 0, false, &t) >= 0)
+ free_and_replace(c->cmdline, t);
+
+ if (get_process_capeff(c->pid, &t) >= 0)
+ free_and_replace(c->capeff, t);
+}
+
+static int client_context_read_label(
+ ClientContext *c,
+ const char *label, size_t label_size) {
+
+ assert(c);
+ assert(pid_is_valid(c->pid));
+ assert(label_size == 0 || label);
+
+ if (label_size > 0) {
+ char *l;
+
+ /* If we got an SELinux label passed in it counts. */
+
+ l = newdup_suffix0(char, label, label_size);
+ if (!l)
+ return -ENOMEM;
+
+ free_and_replace(c->label, l);
+ c->label_size = label_size;
+ }
+#if HAVE_SELINUX
+ else {
+ char *con;
+
+ /* If we got no SELinux label passed in, let's try to acquire one */
+
+ if (getpidcon(c->pid, &con) >= 0) {
+ free_and_replace(c->label, con);
+ c->label_size = strlen(c->label);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int client_context_read_cgroup(Server *s, ClientContext *c, const char *unit_id) {
+ char *t = NULL;
+ int r;
+
+ assert(c);
+
+ /* Try to acquire the current cgroup path */
+ r = cg_pid_get_path_shifted(c->pid, s->cgroup_root, &t);
+ if (r < 0) {
+
+ /* If that didn't work, we use the unit ID passed in as fallback, if we have nothing cached yet */
+ if (unit_id && !c->unit) {
+ c->unit = strdup(unit_id);
+ if (c->unit)
+ return 0;
+ }
+
+ return r;
+ }
+
+ /* Let's shortcut this if the cgroup path didn't change */
+ if (streq_ptr(c->cgroup, t)) {
+ free(t);
+ return 0;
+ }
+
+ free_and_replace(c->cgroup, t);
+
+ (void) cg_path_get_session(c->cgroup, &t);
+ free_and_replace(c->session, t);
+
+ if (cg_path_get_owner_uid(c->cgroup, &c->owner_uid) < 0)
+ c->owner_uid = UID_INVALID;
+
+ (void) cg_path_get_unit(c->cgroup, &t);
+ free_and_replace(c->unit, t);
+
+ (void) cg_path_get_user_unit(c->cgroup, &t);
+ free_and_replace(c->user_unit, t);
+
+ (void) cg_path_get_slice(c->cgroup, &t);
+ free_and_replace(c->slice, t);
+
+ (void) cg_path_get_user_slice(c->cgroup, &t);
+ free_and_replace(c->user_slice, t);
+
+ return 0;
+}
+
+static int client_context_read_invocation_id(
+ Server *s,
+ ClientContext *c) {
+
+ _cleanup_free_ char *escaped = NULL, *slice_path = NULL;
+ char ids[SD_ID128_STRING_MAX];
+ const char *p;
+ int r;
+
+ assert(s);
+ assert(c);
+
+ /* Read the invocation ID of a unit off a unit. It's stored in the "trusted.invocation_id" extended attribute
+ * on the cgroup path. */
+
+ if (!c->unit || !c->slice)
+ return 0;
+
+ r = cg_slice_to_path(c->slice, &slice_path);
+ if (r < 0)
+ return r;
+
+ escaped = cg_escape(c->unit);
+ if (!escaped)
+ return -ENOMEM;
+
+ p = strjoina(s->cgroup_root, "/", slice_path, "/", escaped);
+ if (!p)
+ return -ENOMEM;
+
+ r = cg_get_xattr(SYSTEMD_CGROUP_CONTROLLER, p, "trusted.invocation_id", ids, 32);
+ if (r < 0)
+ return r;
+ if (r != 32)
+ return -EINVAL;
+ ids[32] = 0;
+
+ return sd_id128_from_string(ids, &c->invocation_id);
+}
+
+static void client_context_really_refresh(
+ Server *s,
+ ClientContext *c,
+ const struct ucred *ucred,
+ const char *label, size_t label_size,
+ const char *unit_id,
+ usec_t timestamp) {
+
+ assert(s);
+ assert(c);
+ assert(pid_is_valid(c->pid));
+
+ if (timestamp == USEC_INFINITY)
+ timestamp = now(CLOCK_MONOTONIC);
+
+ client_context_read_uid_gid(c, ucred);
+ client_context_read_basic(c);
+ (void) client_context_read_label(c, label, label_size);
+
+ (void) audit_session_from_pid(c->pid, &c->auditid);
+ (void) audit_loginuid_from_pid(c->pid, &c->loginuid);
+
+ (void) client_context_read_cgroup(s, c, unit_id);
+ (void) client_context_read_invocation_id(s, c);
+
+ c->timestamp = timestamp;
+
+ if (c->in_lru) {
+ assert(c->n_ref == 0);
+ assert_se(prioq_reshuffle(s->client_contexts_lru, c, &c->lru_index) >= 0);
+ }
+}
+
+void client_context_maybe_refresh(
+ Server *s,
+ ClientContext *c,
+ const struct ucred *ucred,
+ const char *label, size_t label_size,
+ const char *unit_id,
+ usec_t timestamp) {
+
+ assert(s);
+ assert(c);
+
+ if (timestamp == USEC_INFINITY)
+ timestamp = now(CLOCK_MONOTONIC);
+
+ /* No cached data so far? Let's fill it up */
+ if (c->timestamp == USEC_INFINITY)
+ goto refresh;
+
+ /* If the data isn't pinned and if the cashed data is older than the upper limit, we flush it out
+ * entirely. This follows the logic that as long as an entry is pinned the PID reuse is unlikely. */
+ if (c->n_ref == 0 && c->timestamp + MAX_USEC < timestamp) {
+ client_context_reset(c);
+ goto refresh;
+ }
+
+ /* If the data is older than the lower limit, we refresh, but keep the old data for all we can't update */
+ if (c->timestamp + REFRESH_USEC < timestamp)
+ goto refresh;
+
+ /* If the data passed along doesn't match the cached data we also do a refresh */
+ if (ucred && uid_is_valid(ucred->uid) && c->uid != ucred->uid)
+ goto refresh;
+
+ if (ucred && gid_is_valid(ucred->gid) && c->gid != ucred->gid)
+ goto refresh;
+
+ if (label_size > 0 && (label_size != c->label_size || memcmp(label, c->label, label_size) != 0))
+ goto refresh;
+
+ return;
+
+refresh:
+ client_context_really_refresh(s, c, ucred, label, label_size, unit_id, timestamp);
+}
+
+static void client_context_try_shrink_to(Server *s, size_t limit) {
+ assert(s);
+
+ /* Bring the number of cache entries below the indicated limit, so that we can create a new entry without
+ * breaching the limit. Note that we only flush out entries that aren't pinned here. This means the number of
+ * cache entries may very well grow beyond the limit, if all entries stored remain pinned. */
+
+ while (hashmap_size(s->client_contexts) > limit) {
+ ClientContext *c;
+
+ c = prioq_pop(s->client_contexts_lru);
+ if (!c)
+ break; /* All remaining entries are pinned, give up */
+
+ assert(c->in_lru);
+ assert(c->n_ref == 0);
+
+ c->in_lru = false;
+
+ client_context_free(s, c);
+ }
+}
+
+void client_context_flush_all(Server *s) {
+ assert(s);
+
+ /* Flush out all remaining entries. This assumes all references are already dropped. */
+
+ s->my_context = client_context_release(s, s->my_context);
+ s->pid1_context = client_context_release(s, s->pid1_context);
+
+ client_context_try_shrink_to(s, 0);
+
+ assert(prioq_size(s->client_contexts_lru) == 0);
+ assert(hashmap_size(s->client_contexts) == 0);
+
+ s->client_contexts_lru = prioq_free(s->client_contexts_lru);
+ s->client_contexts = hashmap_free(s->client_contexts);
+}
+
+static int client_context_get_internal(
+ Server *s,
+ pid_t pid,
+ const struct ucred *ucred,
+ const char *label, size_t label_len,
+ const char *unit_id,
+ bool add_ref,
+ ClientContext **ret) {
+
+ ClientContext *c;
+ int r;
+
+ assert(s);
+ assert(ret);
+
+ if (!pid_is_valid(pid))
+ return -EINVAL;
+
+ c = hashmap_get(s->client_contexts, PID_TO_PTR(pid));
+ if (c) {
+
+ if (add_ref) {
+ if (c->in_lru) {
+ /* The entry wasn't pinned so far, let's remove it from the LRU list then */
+ assert(c->n_ref == 0);
+ assert_se(prioq_remove(s->client_contexts_lru, c, &c->lru_index) >= 0);
+ c->in_lru = false;
+ }
+
+ c->n_ref++;
+ }
+
+ client_context_maybe_refresh(s, c, ucred, label, label_len, unit_id, USEC_INFINITY);
+
+ *ret = c;
+ return 0;
+ }
+
+ client_context_try_shrink_to(s, CACHE_MAX-1);
+
+ r = client_context_new(s, pid, &c);
+ if (r < 0)
+ return r;
+
+ if (add_ref)
+ c->n_ref++;
+ else {
+ r = prioq_put(s->client_contexts_lru, c, &c->lru_index);
+ if (r < 0) {
+ client_context_free(s, c);
+ return r;
+ }
+
+ c->in_lru = true;
+ }
+
+ client_context_really_refresh(s, c, ucred, label, label_len, unit_id, USEC_INFINITY);
+
+ *ret = c;
+ return 0;
+}
+
+int client_context_get(
+ Server *s,
+ pid_t pid,
+ const struct ucred *ucred,
+ const char *label, size_t label_len,
+ const char *unit_id,
+ ClientContext **ret) {
+
+ return client_context_get_internal(s, pid, ucred, label, label_len, unit_id, false, ret);
+}
+
+int client_context_acquire(
+ Server *s,
+ pid_t pid,
+ const struct ucred *ucred,
+ const char *label, size_t label_len,
+ const char *unit_id,
+ ClientContext **ret) {
+
+ return client_context_get_internal(s, pid, ucred, label, label_len, unit_id, true, ret);
+};
+
+ClientContext *client_context_release(Server *s, ClientContext *c) {
+ assert(s);
+
+ if (!c)
+ return NULL;
+
+ assert(c->n_ref > 0);
+ assert(!c->in_lru);
+
+ c->n_ref--;
+ if (c->n_ref > 0)
+ return NULL;
+
+ /* The entry is not pinned anymore, let's add it to the LRU prioq if we can. If we can't we'll drop it
+ * right-away */
+
+ if (prioq_put(s->client_contexts_lru, c, &c->lru_index) < 0)
+ client_context_free(s, c);
+ else
+ c->in_lru = true;
+
+ return NULL;
+}
+
+void client_context_acquire_default(Server *s) {
+ int r;
+
+ assert(s);
+
+ /* Ensure that our own and PID1's contexts are always pinned. Our own context is particularly useful to
+ * generate driver messages. */
+
+ if (!s->my_context) {
+ struct ucred ucred = {
+ .pid = getpid_cached(),
+ .uid = getuid(),
+ .gid = getgid(),
+ };
+
+ r = client_context_acquire(s, ucred.pid, &ucred, NULL, 0, NULL, &s->my_context);
+ if (r < 0)
+ log_warning_errno(r, "Failed to acquire our own context, ignoring: %m");
+ }
+
+ if (!s->pid1_context) {
+
+ r = client_context_acquire(s, 1, NULL, NULL, 0, NULL, &s->pid1_context);
+ if (r < 0)
+ log_warning_errno(r, "Failed to acquire PID1's context, ignoring: %m");
+
+ }
+}
diff --git a/src/journal/journald-context.h b/src/journal/journald-context.h
new file mode 100644
index 0000000000..eb1e21926a
--- /dev/null
+++ b/src/journal/journald-context.h
@@ -0,0 +1,92 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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 <inttypes.h>
+#include <sys/types.h>
+
+#include "sd-id128.h"
+
+typedef struct ClientContext ClientContext;
+
+#include "journald-server.h"
+
+struct ClientContext {
+ unsigned n_ref;
+ unsigned lru_index;
+ usec_t timestamp;
+ bool in_lru;
+
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+
+ char *comm;
+ char *exe;
+ char *cmdline;
+ char *capeff;
+
+ uint32_t auditid;
+ uid_t loginuid;
+
+ char *cgroup;
+ char *session;
+ uid_t owner_uid;
+
+ char *unit;
+ char *user_unit;
+
+ char *slice;
+ char *user_slice;
+
+ sd_id128_t invocation_id;
+
+ char *label;
+ size_t label_size;
+};
+
+int client_context_get(
+ Server *s,
+ pid_t pid,
+ const struct ucred *ucred,
+ const char *label, size_t label_len,
+ const char *unit_id,
+ ClientContext **ret);
+
+int client_context_acquire(
+ Server *s,
+ pid_t pid,
+ const struct ucred *ucred,
+ const char *label, size_t label_len,
+ const char *unit_id,
+ ClientContext **ret);
+
+ClientContext* client_context_release(Server *s, ClientContext *c);
+
+void client_context_maybe_refresh(
+ Server *s,
+ ClientContext *c,
+ const struct ucred *ucred,
+ const char *label, size_t label_size,
+ const char *unit_id,
+ usec_t tstamp);
+
+void client_context_acquire_default(Server *s);
+void client_context_flush_all(Server *s);
diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf
index 654fd76a4b..6b05bda0ae 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/journal/journald-gperf.gperf
@@ -18,6 +18,7 @@ struct ConfigPerfItem;
Journal.Storage, config_parse_storage, 0, offsetof(Server, storage)
Journal.Compress, config_parse_bool, 0, offsetof(Server, compress)
Journal.Seal, config_parse_bool, 0, offsetof(Server, seal)
+Journal.ReadKMsg, config_parse_bool, 0, offsetof(Server, read_kmsg)
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
# The following is a legacy name for compatibility
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval)
@@ -44,3 +45,4 @@ Journal.MaxLevelKMsg, config_parse_log_level, 0, offsetof(Server, max_lev
Journal.MaxLevelConsole, config_parse_log_level, 0, offsetof(Server, max_level_console)
Journal.MaxLevelWall, config_parse_log_level, 0, offsetof(Server, max_level_wall)
Journal.SplitMode, config_parse_split_mode, 0, offsetof(Server, split_mode)
+Journal.LineMax, config_parse_line_max, 0, offsetof(Server, line_max)
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 90658a2ac6..f00313ba08 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -26,6 +26,7 @@
#include "libudev.h"
#include "sd-messages.h"
+#include "alloc-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
@@ -45,11 +46,11 @@ void server_forward_kmsg(
const char *message,
const struct ucred *ucred) {
+ _cleanup_free_ char *ident_buf = NULL;
struct iovec iovec[5];
char header_priority[DECIMAL_STR_MAX(priority) + 3],
header_pid[sizeof("[]: ")-1 + DECIMAL_STR_MAX(pid_t) + 1];
int n = 0;
- char *ident_buf = NULL;
assert(s);
assert(priority >= 0);
@@ -68,7 +69,7 @@ void server_forward_kmsg(
/* First: priority field */
xsprintf(header_priority, "<%i>", priority);
- IOVEC_SET_STRING(iovec[n++], header_priority);
+ iovec[n++] = IOVEC_MAKE_STRING(header_priority);
/* Second: identifier and PID */
if (ucred) {
@@ -80,22 +81,20 @@ void server_forward_kmsg(
xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
if (identifier)
- IOVEC_SET_STRING(iovec[n++], identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
- IOVEC_SET_STRING(iovec[n++], header_pid);
+ iovec[n++] = IOVEC_MAKE_STRING(header_pid);
} else if (identifier) {
- IOVEC_SET_STRING(iovec[n++], identifier);
- IOVEC_SET_STRING(iovec[n++], ": ");
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(": ");
}
/* Fourth: message */
- IOVEC_SET_STRING(iovec[n++], message);
- IOVEC_SET_STRING(iovec[n++], "\n");
+ iovec[n++] = IOVEC_MAKE_STRING(message);
+ iovec[n++] = IOVEC_MAKE_STRING("\n");
if (writev(s->dev_kmsg_fd, iovec, n) < 0)
log_debug_errno(errno, "Failed to write to /dev/kmsg for logging: %m");
-
- free(ident_buf);
}
static bool is_us(const char *pid) {
@@ -106,16 +105,16 @@ static bool is_us(const char *pid) {
if (parse_pid(pid, &t) < 0)
return false;
- return t == getpid();
+ return t == getpid_cached();
}
static void dev_kmsg_record(Server *s, const char *p, size_t l) {
struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
- char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
+ _cleanup_free_ char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL, *identifier = NULL, *pid = NULL;
int priority, r;
unsigned n = 0, z = 0, j;
unsigned long long usec;
- char *identifier = NULL, *pid = NULL, *e, *f, *k;
+ char *e, *f, *k;
uint64_t serial;
size_t pl;
char *kernel_device = NULL;
@@ -216,7 +215,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (startswith(m, "_KERNEL_DEVICE="))
kernel_device = m + 15;
- IOVEC_SET_STRING(iovec[n++], m);
+ iovec[n++] = IOVEC_MAKE_STRING(m);
z++;
l -= (e - k) + 1;
@@ -236,7 +235,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (g) {
b = strappend("_UDEV_DEVNODE=", g);
if (b) {
- IOVEC_SET_STRING(iovec[n++], b);
+ iovec[n++] = IOVEC_MAKE_STRING(b);
z++;
}
}
@@ -245,7 +244,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (g) {
b = strappend("_UDEV_SYSNAME=", g);
if (b) {
- IOVEC_SET_STRING(iovec[n++], b);
+ iovec[n++] = IOVEC_MAKE_STRING(b);
z++;
}
}
@@ -261,7 +260,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (g) {
b = strappend("_UDEV_DEVLINK=", g);
if (b) {
- IOVEC_SET_STRING(iovec[n++], b);
+ iovec[n++] = IOVEC_MAKE_STRING(b);
z++;
}
}
@@ -274,18 +273,18 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
}
if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu", usec) >= 0)
- IOVEC_SET_STRING(iovec[n++], source_time);
+ iovec[n++] = IOVEC_MAKE_STRING(source_time);
- IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
+ iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=kernel");
if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
- IOVEC_SET_STRING(iovec[n++], syslog_priority);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_priority);
if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
- IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_facility);
if ((priority & LOG_FACMASK) == LOG_KERN)
- IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
+ iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=kernel");
else {
pl -= syslog_parse_identifier((const char**) &p, &identifier, &pid);
@@ -297,33 +296,24 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (identifier) {
syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
if (syslog_identifier)
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
}
if (pid) {
syslog_pid = strappend("SYSLOG_PID=", pid);
if (syslog_pid)
- IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_pid);
}
}
if (cunescape_length_with_prefix(p, pl, "MESSAGE=", UNESCAPE_RELAX, &message) >= 0)
- IOVEC_SET_STRING(iovec[n++], message);
+ iovec[n++] = IOVEC_MAKE_STRING(message);
- server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
+ server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority, 0);
finish:
for (j = 0; j < z; j++)
free(iovec[j].iov_base);
-
- free(message);
- free(syslog_priority);
- free(syslog_identifier);
- free(syslog_pid);
- free(syslog_facility);
- free(source_time);
- free(identifier);
- free(pid);
}
static int server_read_dev_kmsg(Server *s) {
@@ -345,7 +335,7 @@ static int server_read_dev_kmsg(Server *s) {
return 0;
}
- if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
+ if (IN_SET(errno, EAGAIN, EINTR, EPIPE))
return 0;
return log_error_errno(errno, "Failed to read from kernel: %m");
@@ -399,16 +389,25 @@ static int dispatch_dev_kmsg(sd_event_source *es, int fd, uint32_t revents, void
#endif
int server_open_dev_kmsg(Server *s) {
+ mode_t mode;
assert(s);
- s->dev_kmsg_fd = open("/dev/kmsg", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (s->read_kmsg)
+ mode = O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY;
+ else
+ mode = O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY;
+
+ s->dev_kmsg_fd = open("/dev/kmsg", mode);
if (s->dev_kmsg_fd < 0) {
log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
"Failed to open /dev/kmsg, ignoring: %m");
return 0;
}
+ if (!s->read_kmsg)
+ return 0;
+
// Requested by Profiling Part & PM Part - DISABLE KMSG online handling from journald
#ifdef TIZEN_JOURNALD_KMSG
int r = sd_event_add_io(s->event, &s->dev_kmsg_event_source, s->dev_kmsg_fd, EPOLLIN, dispatch_dev_kmsg, s);
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index abd06b1adc..d45c9c2270 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -37,6 +37,7 @@
#include "memfd-util.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "selinux-util.h"
#include "socket-util.h"
#include "string-util.h"
@@ -142,6 +143,7 @@ static void server_process_entry_meta(
static int server_process_entry(
Server *s,
const void *buffer, size_t *remaining,
+ ClientContext *context,
const struct ucred *ucred,
const struct timeval *tv,
const char *label, size_t label_len) {
@@ -181,7 +183,7 @@ static int server_process_entry(
break;
}
- if (*p == '.' || *p == '#') {
+ if (IN_SET(*p, '.', '#')) {
/* Ignore control commands for now, and
* comments too. */
*remaining -= (e - p) + 1;
@@ -280,7 +282,7 @@ static int server_process_entry(
}
tn = n++;
- IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
+ iovec[tn] = IOVEC_MAKE_STRING("_TRANSPORT=journal");
entry_size += strlen("_TRANSPORT=journal");
if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
@@ -303,7 +305,7 @@ static int server_process_entry(
server_forward_wall(s, priority, identifier, message, ucred);
}
- server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
+ server_dispatch_message(s, iovec, n, m, context, tv, priority, object_pid);
finish:
for (j = 0; j < n; j++) {
@@ -329,16 +331,23 @@ void server_process_native_message(
const struct timeval *tv,
const char *label, size_t label_len) {
- int r;
size_t remaining = buffer_size;
+ ClientContext *context;
+ int r;
assert(s);
assert(buffer || buffer_size == 0);
+ if (ucred && pid_is_valid(ucred->pid)) {
+ r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
+ if (r < 0)
+ log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid);
+ }
+
do {
r = server_process_entry(s,
(const uint8_t*) buffer + (buffer_size - remaining), &remaining,
- ucred, tv, label, label_len);
+ context, ucred, tv, label, label_len);
} while (r == 0);
}
@@ -512,7 +521,7 @@ int server_open_native_socket(Server*s) {
if (r < 0)
return log_error_errno(errno, "SO_PASSCRED failed: %m");
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (mac_selinux_use()) {
r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index f48639cf58..a3404222e0 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -216,6 +216,13 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
assert(id);
+ /* Returns:
+ *
+ * 0 → the log message shall be suppressed,
+ * 1 + n → the log message shall be permitted, and n messages were dropped from the peer before
+ * < 0 → error
+ */
+
if (!r)
return 1;
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 05a1254d4a..00ad168286 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include <sys/ioctl.h>
@@ -51,6 +51,7 @@
#include "journal-internal.h"
#include "journal-vacuum.h"
#include "journald-audit.h"
+#include "journald-context.h"
#include "journald-kmsg.h"
#include "journald-native.h"
#include "journald-rate-limit.h"
@@ -70,8 +71,8 @@
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
-#include "user-util.h"
#include "syslog-util.h"
+#include "user-util.h"
#define USER_JOURNALS_MAX 1024
@@ -87,6 +88,10 @@
/* The period to insert between posting changes for coalescing */
#define POST_CHANGE_TIMER_INTERVAL_USEC (250*USEC_PER_MSEC)
+/* Pick a good default that is likely to fit into AF_UNIX and AF_INET SOCK_DGRAM datagrams, and even leaves some room
+ * for a bit of additional metadata. */
+#define DEFAULT_LINE_MAX (48*1024)
+
static int determine_path_usage(Server *s, const char *path, uint64_t *ret_used, uint64_t *ret_free) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -235,12 +240,12 @@ void server_space_usage_message(Server *s, JournalStorage *storage) {
}
static void server_add_acls(JournalFile *f, uid_t uid) {
-#ifdef HAVE_ACL
+#if HAVE_ACL
int r;
#endif
assert(f);
-#ifdef HAVE_ACL
+#if HAVE_ACL
if (uid <= SYSTEM_UID_MAX)
return;
@@ -312,7 +317,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
(void) cache_space_refresh(s, &s->system_storage);
patch_min_use(&s->system_storage);
} else if (r < 0) {
- if (r != -ENOENT && r != -EROFS)
+ if (!IN_SET(r, -ENOENT, -EROFS))
log_warning_errno(r, "Failed to open system journal: %m");
r = 0;
@@ -714,354 +719,140 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
server_schedule_sync(s, priority);
}
-static int get_invocation_id(const char *cgroup_root, const char *slice, const char *unit, char **ret) {
- _cleanup_free_ char *escaped = NULL, *slice_path = NULL, *p = NULL;
- char *copy, ids[SD_ID128_STRING_MAX];
- int r;
-
- /* Read the invocation ID of a unit off a unit. It's stored in the "trusted.invocation_id" extended attribute
- * on the cgroup path. */
-
- r = cg_slice_to_path(slice, &slice_path);
- if (r < 0)
- return r;
-
- escaped = cg_escape(unit);
- if (!escaped)
- return -ENOMEM;
-
- p = strjoin(cgroup_root, "/", slice_path, "/", escaped);
- if (!p)
- return -ENOMEM;
-
- r = cg_get_xattr(SYSTEMD_CGROUP_CONTROLLER, p, "trusted.invocation_id", ids, 32);
- if (r < 0)
- return r;
- if (r != 32)
- return -EINVAL;
- ids[32] = 0;
+#define IOVEC_ADD_NUMERIC_FIELD(iovec, n, value, type, isset, format, field) \
+ if (isset(value)) { \
+ char *k; \
+ k = newa(char, strlen(field "=") + DECIMAL_STR_MAX(type) + 1); \
+ sprintf(k, field "=" format, value); \
+ iovec[n++] = IOVEC_MAKE_STRING(k); \
+ }
- if (!id128_is_valid(ids))
- return -EINVAL;
+#define IOVEC_ADD_STRING_FIELD(iovec, n, value, field) \
+ if (!isempty(value)) { \
+ char *k; \
+ k = strjoina(field "=", value); \
+ iovec[n++] = IOVEC_MAKE_STRING(k); \
+ }
- copy = strdup(ids);
- if (!copy)
- return -ENOMEM;
+#define IOVEC_ADD_ID128_FIELD(iovec, n, value, field) \
+ if (!sd_id128_is_null(value)) { \
+ char *k; \
+ k = newa(char, strlen(field "=") + SD_ID128_STRING_MAX); \
+ sd_id128_to_string(value, stpcpy(k, field "=")); \
+ iovec[n++] = IOVEC_MAKE_STRING(k); \
+ }
- *ret = copy;
- return 0;
-}
+#define IOVEC_ADD_SIZED_FIELD(iovec, n, value, value_size, field) \
+ if (value_size > 0) { \
+ char *k; \
+ k = newa(char, strlen(field "=") + value_size + 1); \
+ *((char*) mempcpy(stpcpy(k, field "="), value, value_size)) = 0; \
+ iovec[n++] = IOVEC_MAKE_STRING(k); \
+ } \
static void dispatch_message_real(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- const struct ucred *ucred,
+ const ClientContext *c,
const struct timeval *tv,
- const char *label, size_t label_len,
- const char *unit_id,
int priority,
- pid_t object_pid,
- char *cgroup) {
-
- char pid[sizeof("_PID=") + DECIMAL_STR_MAX(pid_t)],
- uid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)],
- gid[sizeof("_GID=") + DECIMAL_STR_MAX(gid_t)],
- owner_uid[sizeof("_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)],
- source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)],
- o_uid[sizeof("OBJECT_UID=") + DECIMAL_STR_MAX(uid_t)],
- o_gid[sizeof("OBJECT_GID=") + DECIMAL_STR_MAX(gid_t)],
- o_owner_uid[sizeof("OBJECT_SYSTEMD_OWNER_UID=") + DECIMAL_STR_MAX(uid_t)];
- uid_t object_uid;
- gid_t object_gid;
- char *x;
- int r;
- char *t, *c;
- uid_t realuid = 0, owner = 0, journal_uid;
- bool owner_valid = false;
-#ifdef HAVE_AUDIT
- char audit_session[sizeof("_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
- audit_loginuid[sizeof("_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)],
- o_audit_session[sizeof("OBJECT_AUDIT_SESSION=") + DECIMAL_STR_MAX(uint32_t)],
- o_audit_loginuid[sizeof("OBJECT_AUDIT_LOGINUID=") + DECIMAL_STR_MAX(uid_t)];
-
- uint32_t audit;
- uid_t loginuid;
-#endif
+ pid_t object_pid) {
+
+ char source_time[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
+ uid_t journal_uid;
+ ClientContext *o;
assert(s);
assert(iovec);
assert(n > 0);
- assert(n + N_IOVEC_META_FIELDS + (object_pid > 0 ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
-
- if (ucred) {
- realuid = ucred->uid;
-
- sprintf(pid, "_PID="PID_FMT, ucred->pid);
- IOVEC_SET_STRING(iovec[n++], pid);
-
- sprintf(uid, "_UID="UID_FMT, ucred->uid);
- IOVEC_SET_STRING(iovec[n++], uid);
-
- sprintf(gid, "_GID="GID_FMT, ucred->gid);
- IOVEC_SET_STRING(iovec[n++], gid);
-
- r = get_process_comm(ucred->pid, &t);
- if (r >= 0) {
- x = strjoina("_COMM=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- r = get_process_exe(ucred->pid, &t);
- if (r >= 0) {
- x = strjoina("_EXE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- r = get_process_cmdline(ucred->pid, 0, false, &t);
- if (r >= 0) {
- x = strjoina("_CMDLINE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- r = get_process_capeff(ucred->pid, &t);
- if (r >= 0) {
- x = strjoina("_CAP_EFFECTIVE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
-#ifdef HAVE_AUDIT
- r = audit_session_from_pid(ucred->pid, &audit);
- if (r >= 0) {
- sprintf(audit_session, "_AUDIT_SESSION=%"PRIu32, audit);
- IOVEC_SET_STRING(iovec[n++], audit_session);
- }
-
- r = audit_loginuid_from_pid(ucred->pid, &loginuid);
- if (r >= 0) {
- sprintf(audit_loginuid, "_AUDIT_LOGINUID="UID_FMT, loginuid);
- IOVEC_SET_STRING(iovec[n++], audit_loginuid);
- }
-#endif
-
- r = 0;
- if (cgroup)
- c = cgroup;
- else
- r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &c);
-
- if (r >= 0) {
- _cleanup_free_ char *raw_unit = NULL, *raw_slice = NULL;
- char *session = NULL;
-
- x = strjoina("_SYSTEMD_CGROUP=", c);
- IOVEC_SET_STRING(iovec[n++], x);
-
- r = cg_path_get_session(c, &t);
- if (r >= 0) {
- session = strjoina("_SYSTEMD_SESSION=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], session);
- }
-
- if (cg_path_get_owner_uid(c, &owner) >= 0) {
- owner_valid = true;
-
- sprintf(owner_uid, "_SYSTEMD_OWNER_UID="UID_FMT, owner);
- IOVEC_SET_STRING(iovec[n++], owner_uid);
- }
-
- if (cg_path_get_unit(c, &raw_unit) >= 0) {
- x = strjoina("_SYSTEMD_UNIT=", raw_unit);
- IOVEC_SET_STRING(iovec[n++], x);
- } else if (unit_id && !session) {
- x = strjoina("_SYSTEMD_UNIT=", unit_id);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- if (cg_path_get_user_unit(c, &t) >= 0) {
- x = strjoina("_SYSTEMD_USER_UNIT=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- } else if (unit_id && session) {
- x = strjoina("_SYSTEMD_USER_UNIT=", unit_id);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- if (cg_path_get_slice(c, &raw_slice) >= 0) {
- x = strjoina("_SYSTEMD_SLICE=", raw_slice);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- if (cg_path_get_user_slice(c, &t) >= 0) {
- x = strjoina("_SYSTEMD_USER_SLICE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ assert(n + N_IOVEC_META_FIELDS + (pid_is_valid(object_pid) ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
- if (raw_slice && raw_unit) {
- if (get_invocation_id(s->cgroup_root, raw_slice, raw_unit, &t) >= 0) {
- x = strjoina("_SYSTEMD_INVOCATION_ID=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
- }
+ if (c) {
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->pid, pid_t, pid_is_valid, PID_FMT, "_PID");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->uid, uid_t, uid_is_valid, UID_FMT, "_UID");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->gid, gid_t, gid_is_valid, GID_FMT, "_GID");
- if (!cgroup)
- free(c);
- } else if (unit_id) {
- x = strjoina("_SYSTEMD_UNIT=", unit_id);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->comm, "_COMM");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->exe, "_EXE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->cmdline, "_CMDLINE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->capeff, "_CAP_EFFECTIVE");
-#ifdef HAVE_SELINUX
- if (mac_selinux_use()) {
- if (label) {
- x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1);
+ IOVEC_ADD_SIZED_FIELD(iovec, n, c->label, c->label_size, "_SELINUX_CONTEXT");
- *((char*) mempcpy(stpcpy(x, "_SELINUX_CONTEXT="), label, label_len)) = 0;
- IOVEC_SET_STRING(iovec[n++], x);
- } else {
- char *con;
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "_AUDIT_SESSION");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->loginuid, uid_t, uid_is_valid, UID_FMT, "_AUDIT_LOGINUID");
- if (getpidcon(ucred->pid, &con) >= 0) {
- x = strjoina("_SELINUX_CONTEXT=", con);
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->cgroup, "_SYSTEMD_CGROUP");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->session, "_SYSTEMD_SESSION");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, c->owner_uid, uid_t, uid_is_valid, UID_FMT, "_SYSTEMD_OWNER_UID");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->unit, "_SYSTEMD_UNIT");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->user_unit, "_SYSTEMD_USER_UNIT");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->slice, "_SYSTEMD_SLICE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, c->user_slice, "_SYSTEMD_USER_SLICE");
- freecon(con);
- IOVEC_SET_STRING(iovec[n++], x);
- }
- }
- }
-#endif
+ IOVEC_ADD_ID128_FIELD(iovec, n, c->invocation_id, "_SYSTEMD_INVOCATION_ID");
}
- assert(n <= m);
-
- if (object_pid) {
- r = get_process_uid(object_pid, &object_uid);
- if (r >= 0) {
- sprintf(o_uid, "OBJECT_UID="UID_FMT, object_uid);
- IOVEC_SET_STRING(iovec[n++], o_uid);
- }
-
- r = get_process_gid(object_pid, &object_gid);
- if (r >= 0) {
- sprintf(o_gid, "OBJECT_GID="GID_FMT, object_gid);
- IOVEC_SET_STRING(iovec[n++], o_gid);
- }
-
- r = get_process_comm(object_pid, &t);
- if (r >= 0) {
- x = strjoina("OBJECT_COMM=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- r = get_process_exe(object_pid, &t);
- if (r >= 0) {
- x = strjoina("OBJECT_EXE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-
- r = get_process_cmdline(object_pid, 0, false, &t);
- if (r >= 0) {
- x = strjoina("OBJECT_CMDLINE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
-#ifdef HAVE_AUDIT
- r = audit_session_from_pid(object_pid, &audit);
- if (r >= 0) {
- sprintf(o_audit_session, "OBJECT_AUDIT_SESSION=%"PRIu32, audit);
- IOVEC_SET_STRING(iovec[n++], o_audit_session);
- }
-
- r = audit_loginuid_from_pid(object_pid, &loginuid);
- if (r >= 0) {
- sprintf(o_audit_loginuid, "OBJECT_AUDIT_LOGINUID="UID_FMT, loginuid);
- IOVEC_SET_STRING(iovec[n++], o_audit_loginuid);
- }
-#endif
+ assert(n <= m);
- r = cg_pid_get_path_shifted(object_pid, s->cgroup_root, &c);
- if (r >= 0) {
- x = strjoina("OBJECT_SYSTEMD_CGROUP=", c);
- IOVEC_SET_STRING(iovec[n++], x);
-
- r = cg_path_get_session(c, &t);
- if (r >= 0) {
- x = strjoina("OBJECT_SYSTEMD_SESSION=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ if (pid_is_valid(object_pid) && client_context_get(s, object_pid, NULL, NULL, 0, NULL, &o) >= 0) {
- if (cg_path_get_owner_uid(c, &owner) >= 0) {
- sprintf(o_owner_uid, "OBJECT_SYSTEMD_OWNER_UID="UID_FMT, owner);
- IOVEC_SET_STRING(iovec[n++], o_owner_uid);
- }
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->pid, pid_t, pid_is_valid, PID_FMT, "OBJECT_PID");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_UID");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->gid, gid_t, gid_is_valid, GID_FMT, "OBJECT_GID");
- if (cg_path_get_unit(c, &t) >= 0) {
- x = strjoina("OBJECT_SYSTEMD_UNIT=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->comm, "OBJECT_COMM");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->exe, "OBJECT_EXE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->cmdline, "OBJECT_CMDLINE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->capeff, "OBJECT_CAP_EFFECTIVE");
- if (cg_path_get_user_unit(c, &t) >= 0) {
- x = strjoina("OBJECT_SYSTEMD_USER_UNIT=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ IOVEC_ADD_SIZED_FIELD(iovec, n, o->label, o->label_size, "OBJECT_SELINUX_CONTEXT");
- if (cg_path_get_slice(c, &t) >= 0) {
- x = strjoina("OBJECT_SYSTEMD_SLICE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->auditid, uint32_t, audit_session_is_valid, "%" PRIu32, "OBJECT_AUDIT_SESSION");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->loginuid, uid_t, uid_is_valid, UID_FMT, "OBJECT_AUDIT_LOGINUID");
- if (cg_path_get_user_slice(c, &t) >= 0) {
- x = strjoina("OBJECT_SYSTEMD_USER_SLICE=", t);
- free(t);
- IOVEC_SET_STRING(iovec[n++], x);
- }
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->cgroup, "OBJECT_SYSTEMD_CGROUP");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->session, "OBJECT_SYSTEMD_SESSION");
+ IOVEC_ADD_NUMERIC_FIELD(iovec, n, o->owner_uid, uid_t, uid_is_valid, UID_FMT, "OBJECT_SYSTEMD_OWNER_UID");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->unit, "OBJECT_SYSTEMD_UNIT");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->user_unit, "OBJECT_SYSTEMD_USER_UNIT");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->slice, "OBJECT_SYSTEMD_SLICE");
+ IOVEC_ADD_STRING_FIELD(iovec, n, o->user_slice, "OBJECT_SYSTEMD_USER_SLICE");
- free(c);
- }
+ IOVEC_ADD_ID128_FIELD(iovec, n, o->invocation_id, "OBJECT_SYSTEMD_INVOCATION_ID=");
}
+
assert(n <= m);
if (tv) {
sprintf(source_time, "_SOURCE_REALTIME_TIMESTAMP=" USEC_FMT, timeval_load(tv));
- IOVEC_SET_STRING(iovec[n++], source_time);
+ iovec[n++] = IOVEC_MAKE_STRING(source_time);
}
/* Note that strictly speaking storing the boot id here is
* redundant since the entry includes this in-line
* anyway. However, we need this indexed, too. */
if (!isempty(s->boot_id_field))
- IOVEC_SET_STRING(iovec[n++], s->boot_id_field);
+ iovec[n++] = IOVEC_MAKE_STRING(s->boot_id_field);
if (!isempty(s->machine_id_field))
- IOVEC_SET_STRING(iovec[n++], s->machine_id_field);
+ iovec[n++] = IOVEC_MAKE_STRING(s->machine_id_field);
if (!isempty(s->hostname_field))
- IOVEC_SET_STRING(iovec[n++], s->hostname_field);
+ iovec[n++] = IOVEC_MAKE_STRING(s->hostname_field);
assert(n <= m);
- if (s->split_mode == SPLIT_UID && realuid > 0)
- /* Split up strictly by any UID */
- journal_uid = realuid;
- else if (s->split_mode == SPLIT_LOGIN && realuid > 0 && owner_valid && owner > 0)
+ if (s->split_mode == SPLIT_UID && c && uid_is_valid(c->uid))
+ /* Split up strictly by (non-root) UID */
+ journal_uid = c->uid;
+ else if (s->split_mode == SPLIT_LOGIN && c && c->uid > 0 && uid_is_valid(c->owner_uid))
/* Split up by login UIDs. We do this only if the
* realuid is not root, in order not to accidentally
* leak privileged information to the user that is
* logged by a privileged process that is part of an
* unprivileged session. */
- journal_uid = owner;
+ journal_uid = c->owner_uid;
else
journal_uid = 0;
@@ -1069,25 +860,25 @@ static void dispatch_message_real(
}
void server_driver_message(Server *s, const char *message_id, const char *format, ...) {
+
struct iovec iovec[N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS];
unsigned n = 0, m;
- int r;
va_list ap;
- struct ucred ucred = {};
+ int r;
assert(s);
assert(format);
assert_cc(3 == LOG_FAC(LOG_DAEMON));
- IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3");
- IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald");
+ iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_FACILITY=3");
+ iovec[n++] = IOVEC_MAKE_STRING("SYSLOG_IDENTIFIER=systemd-journald");
- IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
+ iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=driver");
assert_cc(6 == LOG_INFO);
- IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
+ iovec[n++] = IOVEC_MAKE_STRING("PRIORITY=6");
if (message_id)
- IOVEC_SET_STRING(iovec[n++], message_id);
+ iovec[n++] = IOVEC_MAKE_STRING(message_id);
m = n;
va_start(ap, format);
@@ -1095,12 +886,8 @@ void server_driver_message(Server *s, const char *message_id, const char *format
/* Error handling below */
va_end(ap);
- ucred.pid = getpid();
- ucred.uid = getuid();
- ucred.gid = getgid();
-
if (r >= 0)
- dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0, NULL);
+ dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), s->my_context, NULL, LOG_INFO, 0);
while (m < n)
free(iovec[m++].iov_base);
@@ -1112,26 +899,22 @@ void server_driver_message(Server *s, const char *message_id, const char *format
xsprintf(buf, "MESSAGE=Entry printing failed: %s", strerror(-r));
n = 3;
- IOVEC_SET_STRING(iovec[n++], "PRIORITY=4");
- IOVEC_SET_STRING(iovec[n++], buf);
- dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0, NULL);
+ iovec[n++] = IOVEC_MAKE_STRING("PRIORITY=4");
+ iovec[n++] = IOVEC_MAKE_STRING(buf);
+ dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), s->my_context, NULL, LOG_INFO, 0);
}
}
void server_dispatch_message(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- const struct ucred *ucred,
+ ClientContext *c,
const struct timeval *tv,
- const char *label, size_t label_len,
- const char *unit_id,
int priority,
pid_t object_pid) {
- int rl, r;
- _cleanup_free_ char *path = NULL;
uint64_t available = 0;
- char *c = NULL;
+ int rl;
assert(s);
assert(iovec || n == 0);
@@ -1147,45 +930,21 @@ void server_dispatch_message(
if (s->storage == STORAGE_NONE)
return;
- if (!ucred)
- goto finish;
+ if (c && c->unit) {
+ (void) determine_space(s, &available, NULL);
- r = cg_pid_get_path_shifted(ucred->pid, s->cgroup_root, &path);
- if (r < 0)
- goto finish;
-
- /* example: /user/lennart/3/foobar
- * /system/dbus.service/foobar
- *
- * So let's cut of everything past the third /, since that is
- * where user directories start */
+ rl = journal_rate_limit_test(s->rate_limit, c->unit, priority & LOG_PRIMASK, available);
+ if (rl == 0)
+ return;
- c = strchr(path, '/');
- if (c) {
- c = strchr(c+1, '/');
- if (c) {
- c = strchr(c+1, '/');
- if (c)
- *c = 0;
- }
+ /* Write a suppression message if we suppressed something */
+ if (rl > 1)
+ server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR,
+ LOG_MESSAGE("Suppressed %u messages from %s", rl - 1, c->unit),
+ NULL);
}
- (void) determine_space(s, &available, NULL);
- rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available);
- if (rl == 0)
- return;
-
- /* Write a suppression message if we suppressed something */
- if (rl > 1)
- server_driver_message(s, "MESSAGE_ID=" SD_MESSAGE_JOURNAL_DROPPED_STR,
- LOG_MESSAGE("Suppressed %u messages from %s", rl - 1, path),
- NULL);
-
-finish:
- /* restore cgroup path for logging */
- if (c)
- *c = '/';
- dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid, path);
+ dispatch_message_real(s, iovec, n, m, c, tv, priority, object_pid);
}
int server_flush_to_var(Server *s, bool require_flag_file) {
@@ -1335,9 +1094,8 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
return -EIO;
}
- /* Try to get the right size, if we can. (Not all
- * sockets support SIOCINQ, hence we just try, but
- * don't rely on it. */
+ /* Try to get the right size, if we can. (Not all sockets support SIOCINQ, hence we just try, but don't rely on
+ * it.) */
(void) ioctl(fd, SIOCINQ, &v);
/* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
@@ -1353,7 +1111,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
return 0;
return log_error_errno(errno, "recvmsg() failed: %m");
@@ -1862,7 +1620,7 @@ static int server_connect_notify(Server *s) {
if (!e)
return 0;
- if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+ if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
log_error("NOTIFY_SOCKET set to an invalid value: %s", e);
return -EINVAL;
}
@@ -1915,6 +1673,7 @@ int server_init(Server *s) {
s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
s->compress = true;
s->seal = true;
+ s->read_kmsg = true;
s->watchdog_usec = USEC_INFINITY;
@@ -1934,6 +1693,8 @@ int server_init(Server *s) {
s->max_level_console = LOG_INFO;
s->max_level_wall = LOG_EMERG;
+ s->line_max = DEFAULT_LINE_MAX;
+
journal_reset_metrics(&s->system_storage.metrics);
journal_reset_metrics(&s->runtime_storage.metrics);
@@ -2051,7 +1812,7 @@ int server_init(Server *s) {
if (r < 0)
return r;
- /* /dev/ksmg */
+ /* /dev/kmsg */
r = server_open_dev_kmsg(s);
if (r < 0)
return r;
@@ -2101,11 +1862,13 @@ int server_init(Server *s) {
(void) server_connect_notify(s);
+ (void) client_context_acquire_default(s);
+
return system_journal_open(s, false);
}
void server_maybe_append_tags(Server *s) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
JournalFile *f;
Iterator i;
usec_t n;
@@ -2132,6 +1895,8 @@ void server_done(Server *s) {
while (s->stdout_streams)
stdout_stream_free(s->stdout_streams);
+ client_context_flush_all(s);
+
if (s->system_journal)
(void) journal_file_close(s->system_journal);
@@ -2204,3 +1969,55 @@ static const char* const split_mode_table[_SPLIT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
+
+int config_parse_line_max(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ size_t *sz = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue))
+ /* Empty assignment means default */
+ *sz = DEFAULT_LINE_MAX;
+ else {
+ uint64_t v;
+
+ r = parse_size(rvalue, 1024, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (v < 79) {
+ /* Why specify 79 here as minimum line length? Simply, because the most common traditional
+ * terminal size is 80ch, and it might make sense to break one character before the natural
+ * line break would occur on that. */
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too small, clamping to 79: %s", rvalue);
+ *sz = 79;
+ } else if (v > (uint64_t) (SSIZE_MAX-1)) {
+ /* So, why specify SSIZE_MAX-1 here? Because that's one below the largest size value read()
+ * can return, and we need one extra byte for the trailing NUL byte. Of course IRL such large
+ * memory allocations will fail anyway, hence this limit is mostly theoretical anyway, as we'll
+ * fail much earlier anyway. */
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "LineMax= too large, clamping to %" PRIu64 ": %s", (uint64_t) (SSIZE_MAX-1), rvalue);
+ *sz = SSIZE_MAX-1;
+ } else
+ *sz = (size_t) v;
+ }
+
+ return 0;
+}
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 203460c50a..f4bdd588cb 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -28,9 +28,11 @@ typedef struct Server Server;
#include "hashmap.h"
#include "journal-file.h"
+#include "journald-context.h"
#include "journald-rate-limit.h"
#include "journald-stream.h"
#include "list.h"
+#include "prioq.h"
typedef enum Storage {
STORAGE_AUTO,
@@ -112,6 +114,7 @@ struct Server {
bool compress;
bool seal;
+ bool read_kmsg;
bool forward_to_kmsg;
bool forward_to_syslog;
@@ -165,6 +168,15 @@ struct Server {
usec_t watchdog_usec;
usec_t last_realtime_clock;
+
+ size_t line_max;
+
+ /* Caching of client metadata */
+ Hashmap *client_contexts;
+ Prioq *client_contexts_lru;
+
+ ClientContext *my_context; /* the context of journald itself */
+ ClientContext *pid1_context; /* the context of PID 1 */
};
#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
@@ -175,13 +187,14 @@ struct Server {
#define N_IOVEC_OBJECT_FIELDS 14
#define N_IOVEC_PAYLOAD_FIELDS 15
-void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
+void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, ClientContext *c, const struct timeval *tv, int priority, pid_t object_pid);
void server_driver_message(Server *s, const char *message_id, const char *format, ...) _printf_(3,0) _sentinel_;
/* gperf lookup function */
const struct ConfigPerfItem* journald_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
int config_parse_storage(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_line_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
const char *storage_to_string(Storage s) _const_;
Storage storage_from_string(const char *s) _pure_;
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 77551dc14b..54dd096e45 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -20,7 +20,7 @@
#include <stddef.h>
#include <unistd.h>
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
@@ -34,6 +34,7 @@
#include "fileio.h"
#include "io-util.h"
#include "journald-console.h"
+#include "journald-context.h"
#include "journald-kmsg.h"
#include "journald-server.h"
#include "journald-stream.h"
@@ -41,11 +42,13 @@
#include "journald-wall.h"
#include "mkdir.h"
#include "parse-util.h"
+#include "process-util.h"
#include "selinux-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "syslog-util.h"
+#include "unit-name.h"
#define STDOUT_STREAMS_MAX 4096
@@ -60,6 +63,16 @@ typedef enum StdoutStreamState {
STDOUT_STREAM_RUNNING
} StdoutStreamState;
+/* The different types of log record terminators: a real \n was read, a NUL character was read, the maximum line length
+ * was reached, or the end of the stream was reached */
+
+typedef enum LineBreak {
+ LINE_BREAK_NEWLINE,
+ LINE_BREAK_NUL,
+ LINE_BREAK_LINE_MAX,
+ LINE_BREAK_EOF,
+} LineBreak;
+
struct StdoutStream {
Server *server;
StdoutStreamState state;
@@ -79,15 +92,20 @@ struct StdoutStream {
bool fdstore:1;
bool in_notify_queue:1;
- char buffer[LINE_MAX+1];
+ char *buffer;
size_t length;
+ size_t allocated;
sd_event_source *event_source;
char *state_file;
+ ClientContext *context;
+
LIST_FIELDS(StdoutStream, stdout_stream);
LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
+
+ char id_field[sizeof("_STREAM_ID=")-1 + SD_ID128_STRING_MAX];
};
void stdout_stream_free(StdoutStream *s) {
@@ -95,6 +113,10 @@ void stdout_stream_free(StdoutStream *s) {
return;
if (s->server) {
+
+ if (s->context)
+ client_context_release(s->server, s->context);
+
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams--;
LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
@@ -113,6 +135,7 @@ void stdout_stream_free(StdoutStream *s) {
free(s->identifier);
free(s->unit_id);
free(s->state_file);
+ free(s->buffer);
free(s);
}
@@ -163,12 +186,14 @@ static int stdout_stream_save(StdoutStream *s) {
"LEVEL_PREFIX=%i\n"
"FORWARD_TO_SYSLOG=%i\n"
"FORWARD_TO_KMSG=%i\n"
- "FORWARD_TO_CONSOLE=%i\n",
+ "FORWARD_TO_CONSOLE=%i\n"
+ "STREAM_ID=%s\n",
s->priority,
s->level_prefix,
s->forward_to_syslog,
s->forward_to_kmsg,
- s->forward_to_console);
+ s->forward_to_console,
+ s->id_field + strlen("_STREAM_ID="));
if (!isempty(s->identifier)) {
_cleanup_free_ char *escaped;
@@ -225,14 +250,14 @@ fail:
return log_error_errno(r, "Failed to save stream data %s: %m", s->state_file);
}
-static int stdout_stream_log(StdoutStream *s, const char *p) {
- struct iovec iovec[N_IOVEC_META_FIELDS + 5];
+static int stdout_stream_log(StdoutStream *s, const char *p, LineBreak line_break) {
+ struct iovec iovec[N_IOVEC_META_FIELDS + 7];
int priority;
char syslog_priority[] = "PRIORITY=\0";
char syslog_facility[sizeof("SYSLOG_FACILITY=")-1 + DECIMAL_STR_MAX(int) + 1];
_cleanup_free_ char *message = NULL, *syslog_identifier = NULL;
unsigned n = 0;
- size_t label_len;
+ int r;
assert(s);
assert(p);
@@ -257,32 +282,52 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
if (s->server->forward_to_wall)
server_forward_wall(s->server, priority, s->identifier, p, &s->ucred);
- IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=stdout");
+ iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=stdout");
+ iovec[n++] = IOVEC_MAKE_STRING(s->id_field);
syslog_priority[strlen("PRIORITY=")] = '0' + LOG_PRI(priority);
- IOVEC_SET_STRING(iovec[n++], syslog_priority);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_priority);
if (priority & LOG_FACMASK) {
xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
- IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_facility);
}
if (s->identifier) {
syslog_identifier = strappend("SYSLOG_IDENTIFIER=", s->identifier);
if (syslog_identifier)
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
+ }
+
+ if (line_break != LINE_BREAK_NEWLINE) {
+ const char *c;
+
+ /* If this log message was generated due to an uncommon line break then mention this in the log
+ * entry */
+
+ c = line_break == LINE_BREAK_NUL ? "_LINE_BREAK=nul" :
+ line_break == LINE_BREAK_LINE_MAX ? "_LINE_BREAK=line-max" :
+ "_LINE_BREAK=eof";
+ iovec[n++] = IOVEC_MAKE_STRING(c);
}
message = strappend("MESSAGE=", p);
if (message)
- IOVEC_SET_STRING(iovec[n++], message);
+ iovec[n++] = IOVEC_MAKE_STRING(message);
+
+ if (s->context)
+ (void) client_context_maybe_refresh(s->server, s->context, NULL, NULL, 0, NULL, USEC_INFINITY);
+ else if (pid_is_valid(s->ucred.pid)) {
+ r = client_context_acquire(s->server, s->ucred.pid, &s->ucred, s->label, strlen_ptr(s->label), s->unit_id, &s->context);
+ if (r < 0)
+ log_warning_errno(r, "Failed to acquire client context, ignoring: %m");
+ }
- label_len = s->label ? strlen(s->label) : 0;
- server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, s->label, label_len, s->unit_id, priority, 0);
+ server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), s->context, NULL, priority, 0);
return 0;
}
-static int stdout_stream_line(StdoutStream *s, char *p) {
+static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) {
int r;
char *orig;
@@ -292,12 +337,16 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
orig = p;
p = strstrip(p);
+ /* line breaks by NUL, line max length or EOF are not permissible during the negotiation part of the protocol */
+ if (line_break != LINE_BREAK_NEWLINE && s->state != STDOUT_STREAM_RUNNING) {
+ log_warning("Control protocol line not properly terminated.");
+ return -EINVAL;
+ }
+
switch (s->state) {
case STDOUT_STREAM_IDENTIFIER:
- if (isempty(p))
- s->identifier = NULL;
- else {
+ if (!isempty(p)) {
s->identifier = strdup(p);
if (!s->identifier)
return log_oom();
@@ -307,14 +356,12 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
return 0;
case STDOUT_STREAM_UNIT_ID:
- if (s->ucred.uid == 0) {
- if (isempty(p))
- s->unit_id = NULL;
- else {
- s->unit_id = strdup(p);
- if (!s->unit_id)
- return log_oom();
- }
+ if (s->ucred.uid == 0 &&
+ unit_name_is_valid(p, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
+
+ s->unit_id = strdup(p);
+ if (!s->unit_id)
+ return log_oom();
}
s->state = STDOUT_STREAM_PRIORITY;
@@ -378,7 +425,7 @@ static int stdout_stream_line(StdoutStream *s, char *p) {
return 0;
case STDOUT_STREAM_RUNNING:
- return stdout_stream_log(s, orig);
+ return stdout_stream_log(s, orig, line_break);
}
assert_not_reached("Unknown stream state");
@@ -397,21 +444,31 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
/* XXX: This function does nothing if (s->length == 0) */
for (;;) {
- char *end;
+ LineBreak line_break;
size_t skip;
-
- end = memchr(p, '\n', remaining);
- if (end)
- skip = end - p + 1;
- else if (remaining >= sizeof(s->buffer) - 1) {
- end = p + sizeof(s->buffer) - 1;
+ char *end1, *end2;
+
+ end1 = memchr(p, '\n', remaining);
+ end2 = memchr(p, 0, end1 ? (size_t) (end1 - p) : remaining);
+
+ if (end2) {
+ /* We found a NUL terminator */
+ skip = end2 - p + 1;
+ line_break = LINE_BREAK_NUL;
+ } else if (end1) {
+ /* We found a \n terminator */
+ *end1 = 0;
+ skip = end1 - p + 1;
+ line_break = LINE_BREAK_NEWLINE;
+ } else if (remaining >= s->server->line_max) {
+ /* Force a line break after the maximum line length */
+ *(p + s->server->line_max) = 0;
skip = remaining;
+ line_break = LINE_BREAK_LINE_MAX;
} else
break;
- *end = 0;
-
- r = stdout_stream_line(s, p);
+ r = stdout_stream_line(s, p, line_break);
if (r < 0)
return r;
@@ -421,7 +478,7 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
if (force_flush && remaining > 0) {
p[remaining] = 0;
- r = stdout_stream_line(s, p);
+ r = stdout_stream_line(s, p, LINE_BREAK_EOF);
if (r < 0)
return r;
@@ -439,6 +496,7 @@ static int stdout_stream_scan(StdoutStream *s, bool force_flush) {
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
StdoutStream *s = userdata;
+ size_t limit;
ssize_t l;
int r;
@@ -449,9 +507,20 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
goto terminate;
}
- l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length);
- if (l < 0) {
+ /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */
+ if (s->length + 1 >= s->allocated) {
+ if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) {
+ log_oom();
+ goto terminate;
+ }
+ }
+
+ /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also,
+ * always leave room for a terminating NUL we might need to add. */
+ limit = MIN(s->allocated - 1, s->server->line_max);
+ l = read(s->fd, s->buffer + s->length, limit - s->length);
+ if (l < 0) {
if (errno == EAGAIN)
return 0;
@@ -478,11 +547,16 @@ terminate:
static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
_cleanup_(stdout_stream_freep) StdoutStream *stream = NULL;
+ sd_id128_t id;
int r;
assert(s);
assert(fd >= 0);
+ r = sd_id128_randomize(&id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate stream ID: %m");
+
stream = new0(StdoutStream, 1);
if (!stream)
return log_oom();
@@ -490,6 +564,8 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
stream->fd = -1;
stream->priority = LOG_INFO;
+ xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
+
r = getpeercred(fd, &stream->ucred);
if (r < 0)
return log_error_errno(r, "Failed to determine peer credentials: %m");
@@ -563,7 +639,8 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) {
*level_prefix = NULL,
*forward_to_syslog = NULL,
*forward_to_kmsg = NULL,
- *forward_to_console = NULL;
+ *forward_to_console = NULL,
+ *stream_id = NULL;
int r;
assert(stream);
@@ -583,6 +660,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) {
"FORWARD_TO_CONSOLE", &forward_to_console,
"IDENTIFIER", &stream->identifier,
"UNIT", &stream->unit_id,
+ "STREAM_ID", &stream_id,
NULL);
if (r < 0)
return log_error_errno(r, "Failed to read: %s", stream->state_file);
@@ -619,6 +697,14 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) {
stream->forward_to_console = r;
}
+ if (stream_id) {
+ sd_id128_t id;
+
+ r = sd_id128_from_string(stream_id, &id);
+ if (r >= 0)
+ xsprintf(stream->id_field, "_STREAM_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
+ }
+
return 0;
}
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 0685563692..e17561dcaf 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -91,7 +91,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
return;
}
- if (ucred && (errno == ESRCH || errno == EPERM)) {
+ if (ucred && IN_SET(errno, ESRCH, EPERM)) {
struct ucred u;
/* Hmm, presumably the sender process vanished
@@ -99,7 +99,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
* let's fix it as good as we can, and retry */
u = *ucred;
- u.pid = getpid();
+ u.pid = getpid_cached();
memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
@@ -124,7 +124,7 @@ static void forward_syslog_raw(Server *s, int priority, const char *buffer, cons
if (LOG_PRI(priority) > s->max_level_syslog)
return;
- IOVEC_SET_STRING(iovec, buffer);
+ iovec = IOVEC_MAKE_STRING(buffer);
forward_syslog_iovec(s, &iovec, 1, ucred, tv);
}
@@ -135,7 +135,7 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons
int n = 0;
time_t t;
struct tm *tm;
- char *ident_buf = NULL;
+ _cleanup_free_ char *ident_buf = NULL;
assert(s);
assert(priority >= 0);
@@ -147,7 +147,7 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons
/* First: priority field */
xsprintf(header_priority, "<%i>", priority);
- IOVEC_SET_STRING(iovec[n++], header_priority);
+ iovec[n++] = IOVEC_MAKE_STRING(header_priority);
/* Second: timestamp */
t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
@@ -156,7 +156,7 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons
return;
if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
return;
- IOVEC_SET_STRING(iovec[n++], header_time);
+ iovec[n++] = IOVEC_MAKE_STRING(header_time);
/* Third: identifier and PID */
if (ucred) {
@@ -168,20 +168,18 @@ void server_forward_syslog(Server *s, int priority, const char *identifier, cons
xsprintf(header_pid, "["PID_FMT"]: ", ucred->pid);
if (identifier)
- IOVEC_SET_STRING(iovec[n++], identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
- IOVEC_SET_STRING(iovec[n++], header_pid);
+ iovec[n++] = IOVEC_MAKE_STRING(header_pid);
} else if (identifier) {
- IOVEC_SET_STRING(iovec[n++], identifier);
- IOVEC_SET_STRING(iovec[n++], ": ");
+ iovec[n++] = IOVEC_MAKE_STRING(identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(": ");
}
/* Fourth: message */
- IOVEC_SET_STRING(iovec[n++], message);
+ iovec[n++] = IOVEC_MAKE_STRING(message);
forward_syslog_iovec(s, iovec, n, ucred, tv);
-
- free(ident_buf);
}
int syslog_fixup_facility(int priority) {
@@ -327,11 +325,12 @@ void server_process_syslog_message(
char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
- struct iovec iovec[N_IOVEC_META_FIELDS + 6];
- unsigned n = 0;
- int priority = LOG_USER | LOG_INFO;
_cleanup_free_ char *identifier = NULL, *pid = NULL;
+ struct iovec iovec[N_IOVEC_META_FIELDS + 6];
+ int priority = LOG_USER | LOG_INFO, r;
+ ClientContext *context = NULL;
const char *orig;
+ unsigned n = 0;
assert(s);
assert(buf);
@@ -354,31 +353,37 @@ void server_process_syslog_message(
if (s->forward_to_wall)
server_forward_wall(s, priority, identifier, buf, ucred);
- IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
+ iovec[n++] = IOVEC_MAKE_STRING("_TRANSPORT=syslog");
xsprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK);
- IOVEC_SET_STRING(iovec[n++], syslog_priority);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_priority);
if (priority & LOG_FACMASK) {
xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
- IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_facility);
}
if (identifier) {
syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier);
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_identifier);
}
if (pid) {
syslog_pid = strjoina("SYSLOG_PID=", pid);
- IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ iovec[n++] = IOVEC_MAKE_STRING(syslog_pid);
}
message = strjoina("MESSAGE=", buf);
if (message)
- IOVEC_SET_STRING(iovec[n++], message);
+ iovec[n++] = IOVEC_MAKE_STRING(message);
+
+ if (ucred && pid_is_valid(ucred->pid)) {
+ r = client_context_get(s, ucred->pid, ucred, label, label_len, NULL, &context);
+ if (r < 0)
+ log_warning_errno(r, "Failed to retrieve credentials for PID " PID_FMT ", ignoring: %m", ucred->pid);
+ }
- server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
+ server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), context, tv, priority, 0);
}
int server_open_syslog_socket(Server *s) {
@@ -411,7 +416,7 @@ int server_open_syslog_socket(Server *s) {
if (r < 0)
return log_error_errno(errno, "SO_PASSCRED failed: %m");
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (mac_selinux_use()) {
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
diff --git a/src/journal/journald.c b/src/journal/journald.c
index 1aaef387b4..318e067563 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -55,7 +55,7 @@ int main(int argc, char *argv[]) {
server_flush_to_var(&server, true);
server_flush_dev_kmsg(&server);
- log_debug("systemd-journald running as pid "PID_FMT, getpid());
+ log_debug("systemd-journald running as pid "PID_FMT, getpid_cached());
server_driver_message(&server,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_START_STR,
LOG_MESSAGE("Journal started"),
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
t = server.oldest_file_usec + server.max_retention_usec - n;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
if (server.system_journal) {
usec_t u;
@@ -114,7 +114,7 @@ int main(int argc, char *argv[]) {
server_maybe_warn_forward_syslog_missed(&server);
}
- log_debug("systemd-journald stopped as pid "PID_FMT, getpid());
+ log_debug("systemd-journald stopped as pid "PID_FMT, getpid_cached());
server_driver_message(&server,
"MESSAGE_ID=" SD_MESSAGE_JOURNAL_STOP_STR,
LOG_MESSAGE("Journal stopped"),
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 789b6c2d0c..4bbfa2dd6d 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -39,3 +39,4 @@ SystemMaxUse=4M
#MaxLevelKMsg=notice
#MaxLevelConsole=info
#MaxLevelWall=emerg
+#LineMax=48K
diff --git a/src/journal/meson.build b/src/journal/meson.build
index 582f83afb9..da42fd89d2 100644
--- a/src/journal/meson.build
+++ b/src/journal/meson.build
@@ -20,7 +20,7 @@ journal_internal_sources = files('''
sd-journal.c
'''.split())
-if conf.get('HAVE_GCRYPT', false)
+if conf.get('HAVE_GCRYPT') == 1
journal_internal_sources += files('''
journal-authenticate.c
journal-authenticate.h
@@ -36,7 +36,7 @@ endif
audit_type_includes = [config_h,
missing_h,
'linux/audit.h']
-if conf.get('HAVE_AUDIT', false)
+if conf.get('HAVE_AUDIT') == 1
audit_type_includes += 'libaudit.h'
endif
@@ -59,24 +59,26 @@ journal_internal_sources += [audit_type_to_name]
############################################################
libjournal_core_sources = files('''
- journald-kmsg.c
- journald-kmsg.h
- journald-syslog.c
- journald-syslog.h
- journald-stream.c
- journald-stream.h
- journald-server.c
- journald-server.h
+ journald-audit.c
+ journald-audit.h
journald-console.c
journald-console.h
- journald-wall.c
- journald-wall.h
+ journald-context.c
+ journald-context.h
+ journald-kmsg.c
+ journald-kmsg.h
journald-native.c
journald-native.h
- journald-audit.c
- journald-audit.h
journald-rate-limit.c
journald-rate-limit.h
+ journald-server.c
+ journald-server.h
+ journald-stream.c
+ journald-stream.h
+ journald-syslog.c
+ journald-syslog.h
+ journald-wall.c
+ journald-wall.h
journal-internal.h
'''.split())
@@ -95,7 +97,7 @@ systemd_cat_sources = files('cat.c')
journalctl_sources = files('journalctl.c')
-if conf.get('HAVE_QRENCODE', false)
+if conf.get('HAVE_QRENCODE') == 1
journalctl_sources += files('journal-qrcode.c',
'journal-qrcode.h')
endif
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index 5dfda73c56..ac7252093b 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -84,7 +84,7 @@ struct MMapCache {
#define WINDOWS_MIN 64
-#ifdef ENABLE_DEBUG_MMAP_CACHE
+#if ENABLE_DEBUG_MMAP_CACHE
/* Tiny windows increase mmap activity and the chance of exposing unsafe use. */
# define WINDOW_SIZE (page_size())
#else
@@ -157,19 +157,26 @@ static void window_free(Window *w) {
free(w);
}
-_pure_ static bool window_matches(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) {
+_pure_ static inline bool window_matches(Window *w, int prot, uint64_t offset, size_t size) {
assert(w);
- assert(f);
assert(size > 0);
return
- w->fd &&
- f->fd == w->fd->fd &&
prot == w->prot &&
offset >= w->offset &&
offset + size <= w->offset + w->size;
}
+_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) {
+ assert(w);
+ assert(f);
+
+ return
+ w->fd &&
+ f->fd == w->fd->fd &&
+ window_matches(w, prot, offset, size);
+}
+
static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) {
Window *w;
@@ -218,7 +225,7 @@ static void context_detach_window(Context *c) {
if (!w->contexts && !w->keep_always) {
/* Not used anymore? */
-#ifdef ENABLE_DEBUG_MMAP_CACHE
+#if ENABLE_DEBUG_MMAP_CACHE
/* Unmap unused windows immediately to expose use-after-unmap
* by SIGSEGV. */
window_free(w);
@@ -338,7 +345,8 @@ static int try_context(
bool keep_always,
uint64_t offset,
size_t size,
- void **ret) {
+ void **ret,
+ size_t *ret_size) {
Context *c;
@@ -357,7 +365,7 @@ static int try_context(
if (!c->window)
return 0;
- if (!window_matches(c->window, f, prot, offset, size)) {
+ if (!window_matches_fd(c->window, f, prot, offset, size)) {
/* Drop the reference to the window, since it's unnecessary now */
context_detach_window(c);
@@ -370,6 +378,9 @@ static int try_context(
c->window->keep_always = c->window->keep_always || keep_always;
*ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
+ if (ret_size)
+ *ret_size = c->window->size - (offset - c->window->offset);
+
return 1;
}
@@ -381,7 +392,8 @@ static int find_mmap(
bool keep_always,
uint64_t offset,
size_t size,
- void **ret) {
+ void **ret,
+ size_t *ret_size) {
Window *w;
Context *c;
@@ -395,7 +407,7 @@ static int find_mmap(
return -EIO;
LIST_FOREACH(by_fd, w, f->windows)
- if (window_matches(w, f, prot, offset, size))
+ if (window_matches(w, prot, offset, size))
break;
if (!w)
@@ -409,6 +421,9 @@ static int find_mmap(
w->keep_always = w->keep_always || keep_always;
*ret = (uint8_t*) w->ptr + (offset - w->offset);
+ if (ret_size)
+ *ret_size = w->size - (offset - w->offset);
+
return 1;
}
@@ -448,7 +463,8 @@ static int add_mmap(
uint64_t offset,
size_t size,
struct stat *st,
- void **ret) {
+ void **ret,
+ size_t *ret_size) {
uint64_t woffset, wsize;
Context *c;
@@ -503,11 +519,12 @@ static int add_mmap(
if (!w)
goto outofmem;
- context_detach_window(c);
- c->window = w;
- LIST_PREPEND(by_window, w->contexts, c);
+ context_attach_window(c, w);
*ret = (uint8_t*) w->ptr + (offset - w->offset);
+ if (ret_size)
+ *ret_size = w->size - (offset - w->offset);
+
return 1;
outofmem:
@@ -524,7 +541,8 @@ int mmap_cache_get(
uint64_t offset,
size_t size,
struct stat *st,
- void **ret) {
+ void **ret,
+ size_t *ret_size) {
int r;
@@ -536,14 +554,14 @@ int mmap_cache_get(
assert(context < MMAP_CACHE_MAX_CONTEXTS);
/* Check whether the current context is the right one already */
- r = try_context(m, f, prot, context, keep_always, offset, size, ret);
+ r = try_context(m, f, prot, context, keep_always, offset, size, ret, ret_size);
if (r != 0) {
m->n_hit++;
return r;
}
/* Search for a matching mmap */
- r = find_mmap(m, f, prot, context, keep_always, offset, size, ret);
+ r = find_mmap(m, f, prot, context, keep_always, offset, size, ret, ret_size);
if (r != 0) {
m->n_hit++;
return r;
@@ -552,7 +570,7 @@ int mmap_cache_get(
m->n_missed++;
/* Create a new mmap */
- return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret);
+ return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret, ret_size);
}
unsigned mmap_cache_get_hit(MMapCache *m) {
diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
index 7b33218563..cf6af1906a 100644
--- a/src/journal/mmap-cache.h
+++ b/src/journal/mmap-cache.h
@@ -41,7 +41,8 @@ int mmap_cache_get(
uint64_t offset,
size_t size,
struct stat *st,
- void **ret);
+ void **ret,
+ size_t *ret_size);
MMapFileDescriptor * mmap_cache_add_fd(MMapCache *m, int fd);
void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f);
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index cd56470a33..fc86b99e70 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -69,7 +69,7 @@ static bool journal_pid_changed(sd_journal *j) {
/* We don't support people creating a journal object and
* keeping it around over a fork(). Let's complain. */
- return j->original_pid != getpid();
+ return j->original_pid != getpid_cached();
}
static int journal_put_error(sd_journal *j, int r, const char *path) {
@@ -136,7 +136,7 @@ static void reset_location(sd_journal *j) {
static void init_location(Location *l, LocationType type, JournalFile *f, Object *o) {
assert(l);
- assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK);
+ assert(IN_SET(type, LOCATION_DISCRETE, LOCATION_SEEK));
assert(f);
assert(o->object.type == OBJECT_ENTRY);
@@ -450,7 +450,7 @@ _pure_ static int compare_with_location(JournalFile *f, Location *l) {
assert(f);
assert(l);
assert(f->location_type == LOCATION_SEEK);
- assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK);
+ assert(IN_SET(l->type, LOCATION_DISCRETE, LOCATION_SEEK));
if (l->monotonic_set &&
sd_id128_equal(f->current_boot_id, l->boot_id) &&
@@ -1715,7 +1715,7 @@ static sd_journal *journal_new(int flags, const char *path) {
if (!j)
return NULL;
- j->original_pid = getpid();
+ j->original_pid = getpid_cached();
j->toplevel_fd = -1;
j->inotify_fd = -1;
j->flags = flags;
@@ -2152,7 +2152,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
compression = o->object.flags & OBJECT_COMPRESSION_MASK;
if (compression) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
r = decompress_startswith(compression,
o->data.payload, l,
&f->compress_buffer, &f->compress_buffer_size,
@@ -2216,7 +2216,7 @@ static int return_data(sd_journal *j, JournalFile *f, Object *o, const void **da
compression = o->object.flags & OBJECT_COMPRESSION_MASK;
if (compression) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
size_t rsize;
int r;
@@ -2436,7 +2436,7 @@ _public_ int sd_journal_process(sd_journal *j) {
l = read(j->inotify_fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return got_something ? determine_change(j) : SD_JOURNAL_NOP;
return -errno;
diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c
index 4fb93ded73..be5a6655a8 100644
--- a/src/journal/test-compress-benchmark.c
+++ b/src/journal/test-compress-benchmark.c
@@ -19,6 +19,7 @@
#include "alloc-util.h"
#include "compress.h"
+#include "env-util.h"
#include "macro.h"
#include "parse-util.h"
#include "random-util.h"
@@ -30,9 +31,9 @@ typedef int (compress_t)(const void *src, uint64_t src_size, void *dst,
typedef int (decompress_t)(const void *src, uint64_t src_size,
void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max);
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
-static usec_t arg_duration = 2 * USEC_PER_SEC;
+static usec_t arg_duration;
static size_t arg_start;
#define MAX_SIZE (1024*1024LU)
@@ -156,8 +157,9 @@ static void test_compress_decompress(const char* label, const char* type,
#endif
int main(int argc, char *argv[]) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
const char *i;
+ int r;
log_set_max_level(LOG_INFO);
@@ -166,17 +168,25 @@ int main(int argc, char *argv[]) {
assert_se(safe_atou(argv[1], &x) >= 0);
arg_duration = x * USEC_PER_SEC;
+ } else {
+ bool slow;
+
+ r = getenv_bool("SYSTEMD_SLOW_TESTS");
+ slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
+
+ arg_duration = slow ? 2 * USEC_PER_SEC : USEC_PER_SEC / 50;
}
+
if (argc == 3)
(void) safe_atozu(argv[2], &arg_start);
else
- arg_start = getpid();
+ arg_start = getpid_cached();
NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
-#ifdef HAVE_XZ
+#if HAVE_XZ
test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
#endif
}
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index 92108a84b3..893f2ab6eb 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
#include <lz4.h>
#endif
@@ -29,13 +29,13 @@
#include "random-util.h"
#include "util.h"
-#ifdef HAVE_XZ
+#if HAVE_XZ
# define XZ_OK 0
#else
# define XZ_OK -EPROTONOSUPPORT
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
# define LZ4_OK 0
#else
# define LZ4_OK -EPROTONOSUPPORT
@@ -54,7 +54,7 @@ typedef int (decompress_sw_t)(const void *src, uint64_t src_size,
typedef int (compress_stream_t)(int fdf, int fdt, uint64_t max_bytes);
typedef int (decompress_stream_t)(int fdf, int fdt, uint64_t max_size);
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
static void test_compress_decompress(int compression,
compress_blob_t compress,
decompress_blob_t decompress,
@@ -194,7 +194,7 @@ static void test_compress_stream(int compression,
assert_se(lseek(dst, 1, SEEK_SET) == 1);
r = decompress(dst, dst2, st.st_size);
- assert_se(r == -EBADMSG || r == 0);
+ assert_se(IN_SET(r, 0, -EBADMSG));
assert_se(lseek(dst, 0, SEEK_SET) == 0);
assert_se(lseek(dst2, 0, SEEK_SET) == 0);
@@ -206,7 +206,7 @@ static void test_compress_stream(int compression,
}
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
static void test_lz4_decompress_partial(void) {
char buf[20000];
size_t buf_size = sizeof(buf), compressed;
@@ -249,7 +249,7 @@ static void test_lz4_decompress_partial(void) {
#endif
int main(int argc, char *argv[]) {
-#if defined(HAVE_XZ) || defined(HAVE_LZ4)
+#if HAVE_XZ || HAVE_LZ4
const char text[] =
"text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF"
"foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF";
@@ -268,7 +268,7 @@ int main(int argc, char *argv[]) {
random_bytes(data + 7, sizeof(data) - 7);
-#ifdef HAVE_XZ
+#if HAVE_XZ
test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
text, sizeof(text), false);
test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz,
@@ -290,7 +290,7 @@ int main(int argc, char *argv[]) {
log_info("/* XZ test skipped */");
#endif
-#ifdef HAVE_LZ4
+#if HAVE_LZ4
test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
text, sizeof(text), false);
test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4,
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 2543d64b5b..df685e90b6 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -58,7 +58,7 @@ static void test_non_empty(void) {
iovec.iov_len = strlen(test);
assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0);
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
journal_file_append_tag(f);
#endif
journal_file_dump(f);
diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c
index c51b069f8b..702434efd2 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/journal/test-mmap-cache.c
@@ -51,23 +51,23 @@ int main(int argc, char *argv[]) {
assert_se(z >= 0);
unlink(pz);
- r = mmap_cache_get(m, fx, PROT_READ, 0, false, 1, 2, NULL, &p);
+ r = mmap_cache_get(m, fx, PROT_READ, 0, false, 1, 2, NULL, &p, NULL);
assert_se(r >= 0);
- r = mmap_cache_get(m, fx, PROT_READ, 0, false, 2, 2, NULL, &q);
+ r = mmap_cache_get(m, fx, PROT_READ, 0, false, 2, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);
- r = mmap_cache_get(m, fx, PROT_READ, 1, false, 3, 2, NULL, &q);
+ r = mmap_cache_get(m, fx, PROT_READ, 1, false, 3, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 2 == (uint8_t*) q);
- r = mmap_cache_get(m, fx, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p);
+ r = mmap_cache_get(m, fx, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL);
assert_se(r >= 0);
- r = mmap_cache_get(m, fx, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q);
+ r = mmap_cache_get(m, fx, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL);
assert_se(r >= 0);
assert_se((uint8_t*) p + 1 == (uint8_t*) q);
diff --git a/src/kernel-install/Makefile b/src/kernel-install/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/kernel-install/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd-network/Makefile b/src/libsystemd-network/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd-network/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index 65405dcce0..a440a20f96 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -108,14 +108,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
if (r < 0)
return -errno;
- link->ll.sll_family = AF_PACKET;
- link->ll.sll_protocol = htobe16(ETH_P_IP);
- link->ll.sll_ifindex = ifindex;
- link->ll.sll_hatype = htobe16(arp_type);
- link->ll.sll_halen = mac_addr_len;
+ link->ll = (struct sockaddr_ll) {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htobe16(ETH_P_IP),
+ .sll_ifindex = ifindex,
+ .sll_hatype = htobe16(arp_type),
+ .sll_halen = mac_addr_len,
+ };
memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
- r = bind(s, &link->sa, sizeof(link->ll));
+ r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
return -errno;
@@ -221,7 +223,7 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
assert(packet);
assert(len);
- r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll));
+ r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
if (r < 0)
return -errno;
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index 40442b3636..475c5729a0 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -34,8 +34,8 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
size_t offset = 0;
int r;
- assert(op == BOOTREQUEST || op == BOOTREPLY);
- assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND);
+ assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
+ assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
message->op = op;
message->htype = arp_type;
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
index 7fbebd6f27..cf69044d6d 100644
--- a/src/libsystemd-network/icmp6-util.c
+++ b/src/libsystemd-network/icmp6-util.c
@@ -191,7 +191,7 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst,
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h
index b21d4e54cb..5601be844d 100644
--- a/src/libsystemd-network/radv-internal.h
+++ b/src/libsystemd-network/radv-internal.h
@@ -35,12 +35,22 @@ assert_cc(SD_RADV_DEFAULT_MIN_TIMEOUT_USEC <= SD_RADV_DEFAULT_MAX_TIMEOUT_USEC)
#define SD_RADV_MIN_DELAY_BETWEEN_RAS 3
#define SD_RADV_MAX_RA_DELAY_TIME_USEC (500*USEC_PER_MSEC)
+#define SD_RADV_OPT_RDNSS 25
+#define SD_RADV_OPT_DNSSL 31
+
enum RAdvState {
SD_RADV_STATE_IDLE = 0,
SD_RADV_STATE_ADVERTISING = 1,
};
typedef enum RAdvState RAdvState;
+struct sd_radv_opt_dns {
+ uint8_t type;
+ uint8_t length;
+ uint16_t reserved;
+ be32_t lifetime;
+} _packed_;
+
struct sd_radv {
unsigned n_ref;
RAdvState state;
@@ -63,6 +73,10 @@ struct sd_radv {
unsigned n_prefixes;
LIST_HEAD(sd_radv_prefix, prefixes);
+
+ size_t n_rdnss;
+ struct sd_radv_opt_dns *rdnss;
+ struct sd_radv_opt_dns *dnssl;
};
struct sd_radv_prefix {
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index e20d339bd5..29b22eed45 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -62,6 +62,7 @@ struct sd_dhcp_client {
uint8_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_size;
+ bool anonymize;
be32_t last_addr;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
@@ -116,6 +117,32 @@ static const uint8_t default_req_opts[] = {
SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
};
+/* RFC7844 section 3:
+ MAY contain the Parameter Request List option.
+ RFC7844 section 3.6:
+ The client intending to protect its privacy SHOULD only request a
+ minimal number of options in the PRL and SHOULD also randomly shuffle
+ the ordering of option codes in the PRL. If this random ordering
+ cannot be implemented, the client MAY order the option codes in the
+ PRL by option code number (lowest to highest).
+*/
+/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
+static const uint8_t default_req_opts_anonymize[] = {
+ SD_DHCP_OPTION_SUBNET_MASK, /* 1 */
+ SD_DHCP_OPTION_ROUTER, /* 3 */
+ SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */
+ SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */
+ SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */
+ SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */
+ SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */
+ SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */
+ SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */
+ SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */
+ SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */
+ SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */
+ SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */
+};
+
static int client_receive_message_raw(
sd_event_source *s,
int fd,
@@ -428,9 +455,7 @@ int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
assert_return(client, -EINVAL);
- if (client->state != DHCP_STATE_BOUND &&
- client->state != DHCP_STATE_RENEWING &&
- client->state != DHCP_STATE_REBINDING)
+ if (!IN_SET(client->state, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
return -EADDRNOTAVAIL;
if (ret)
@@ -503,7 +528,7 @@ static int client_message_init(
assert(ret);
assert(_optlen);
assert(_optoffset);
- assert(type == DHCP_DISCOVER || type == DHCP_REQUEST);
+ assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST));
optlen = DHCP_MIN_OPTIONS_SIZE;
size = sizeof(DHCPPacket) + optlen;
@@ -588,11 +613,18 @@ static int client_message_init(
it MUST include that list in any subsequent DHCPREQUEST
messages.
*/
- r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
- client->req_opts_size, client->req_opts);
- if (r < 0)
- return r;
+
+ /* RFC7844 section 3:
+ MAY contain the Parameter Request List option. */
+ /* NOTE: in case that there would be an option to do not send
+ * any PRL at all, the size should be checked before sending */
+ if (client->req_opts_size > 0) {
+ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
+ client->req_opts_size, client->req_opts);
+ if (r < 0)
+ return r;
+ }
/* RFC2131 section 3.5:
The client SHOULD include the ’maximum DHCP message size’ option to
@@ -616,12 +648,16 @@ static int client_message_init(
Maximum DHCP Message Size option is the total maximum packet size,
including IP and UDP headers.)
*/
- max_size = htobe16(size);
- r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
- SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
- 2, &max_size);
- if (r < 0)
- return r;
+ /* RFC7844 section 3:
+ SHOULD NOT contain any other option. */
+ if (!client->anonymize) {
+ max_size = htobe16(size);
+ r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
+ SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
+ 2, &max_size);
+ if (r < 0)
+ return r;
+ }
*_optlen = optlen;
*_optoffset = optoffset;
@@ -671,8 +707,7 @@ static int client_send_discover(sd_dhcp_client *client) {
int r;
assert(client);
- assert(client->state == DHCP_STATE_INIT ||
- client->state == DHCP_STATE_SELECTING);
+ assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
r = client_message_init(client, &discover, DHCP_DISCOVER,
&optlen, &optoffset);
@@ -1126,7 +1161,7 @@ static int client_start_delayed(sd_dhcp_client *client) {
}
client->fd = r;
- if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
+ if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
client->start_time = now(clock_boottime_or_monotonic());
return client_initialize_events(client, client_receive_message_raw);
@@ -1652,7 +1687,7 @@ static int client_receive_message_udp(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_dhcp_client_errno(client, errno,
@@ -1746,7 +1781,7 @@ static int client_receive_message_raw(
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_dhcp_client_errno(client, errno,
@@ -1783,7 +1818,14 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
if (r < 0)
return r;
- if (client->last_addr)
+ /* RFC7844 section 3.3:
+ SHOULD perform a complete four-way handshake, starting with a
+ DHCPDISCOVER, to obtain a new address lease. If the client can
+ ascertain that this is exactly the same network to which it was
+ previously connected, and if the link-layer address did not change,
+ the client MAY issue a DHCPREQUEST to try to reclaim the current
+ address. */
+ if (client->last_addr && !client->anonymize)
client->state = DHCP_STATE_INIT_REBOOT;
r = client_start(client);
@@ -1875,7 +1917,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
return mfree(client);
}
-int sd_dhcp_client_new(sd_dhcp_client **ret) {
+int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
_cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
assert_return(ret, -EINVAL);
@@ -1892,8 +1934,15 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) {
client->mtu = DHCP_DEFAULT_MIN_SIZE;
client->port = DHCP_PORT_CLIENT;
- client->req_opts_size = ELEMENTSOF(default_req_opts);
- client->req_opts = memdup(default_req_opts, client->req_opts_size);
+ client->anonymize = !!anonymize;
+ /* NOTE: this could be moved to a function. */
+ if (anonymize) {
+ client->req_opts_size = ELEMENTSOF(default_req_opts_anonymize);
+ client->req_opts = memdup(default_req_opts_anonymize, client->req_opts_size);
+ } else {
+ client->req_opts_size = ELEMENTSOF(default_req_opts);
+ client->req_opts = memdup(default_req_opts, client->req_opts_size);
+ }
if (!client->req_opts)
return -ENOMEM;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 1661874a55..1ab569765d 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -471,7 +471,7 @@ static int lease_parse_routes(
struct sd_dhcp_route *route = *routes + *routes_size;
int r;
- r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
+ r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
if (r < 0) {
log_debug("Failed to determine destination prefix length from class based IP, ignoring");
continue;
@@ -926,16 +926,16 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_dns(lease, &addresses);
if (r > 0) {
- fputs("DNS=", f);
+ fputs_unlocked("DNS=", f);
serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_ntp(lease, &addresses);
if (r > 0) {
- fputs("NTP=", f);
+ fputs_unlocked("NTP=", f);
serialize_in_addrs(f, addresses, r);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_domainname(lease, &string);
@@ -944,9 +944,9 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
if (r > 0) {
- fputs("DOMAIN_SEARCH_LIST=", f);
+ fputs_unlocked("DOMAIN_SEARCH_LIST=", f);
fputstrv(f, search_domains, NULL, NULL);
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
r = sd_dhcp_lease_get_hostname(lease, &string);
@@ -1253,7 +1253,7 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
address.s_addr = lease->address;
/* fall back to the default subnet masks based on address class */
- r = in_addr_default_subnet_mask(&address, &mask);
+ r = in4_addr_default_subnet_mask(&address, &mask);
if (r < 0)
return r;
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 5a59c377f8..663fd0e41d 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -56,7 +56,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
assert_return(address->s_addr != INADDR_ANY, -EINVAL);
assert_return(prefixlen <= 32, -ERANGE);
- assert_se(in_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
+ assert_se(in4_addr_prefixlen_to_netmask(&netmask_addr, prefixlen));
netmask = netmask_addr.s_addr;
server_off = be32toh(address->s_addr & ~netmask);
@@ -993,7 +993,7 @@ static int server_receive_message(sd_event_source *s, int fd,
len = recvmsg(fd, &msg, 0);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 6444b0ce94..eba0c8bcbb 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -940,7 +940,7 @@ static int client_receive_message(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index 2ebc00f247..909b470251 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -354,7 +354,7 @@ static int ipv4acd_on_packet(
n = recv(fd, &packet, sizeof(struct ether_arp), 0);
if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m");
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 39ddb2461a..0f591a8011 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -218,7 +218,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
if (length < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c
index bd03738f30..c42fdce514 100644
--- a/src/libsystemd-network/sd-radv.c
+++ b/src/libsystemd-network/sd-radv.c
@@ -25,12 +25,14 @@
#include "macro.h"
#include "alloc-util.h"
+#include "dns-domain.h"
#include "fd-util.h"
#include "icmp6-util.h"
#include "in-addr-util.h"
#include "radv-internal.h"
#include "socket-util.h"
#include "string-util.h"
+#include "strv.h"
#include "util.h"
#include "random-util.h"
@@ -125,6 +127,9 @@ _public_ sd_radv *sd_radv_unref(sd_radv *ra) {
sd_radv_prefix_unref(p);
}
+ free(ra->rdnss);
+ free(ra->dnssl);
+
radv_reset(ra);
sd_radv_detach_event(ra);
@@ -154,8 +159,8 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
.nd_opt_mtu_type = ND_OPT_MTU,
.nd_opt_mtu_len = 1,
};
- /* Reserve iov space for RA header, linkaddr, MTU + N prefixes */
- struct iovec iov[3 + ra->n_prefixes];
+ /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, RDNSS */
+ struct iovec iov[4 + ra->n_prefixes];
struct msghdr msg = {
.msg_name = &dst_addr,
.msg_namelen = sizeof(dst_addr),
@@ -195,6 +200,18 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst,
msg.msg_iovlen++;
}
+ if (ra->rdnss) {
+ iov[msg.msg_iovlen].iov_base = ra->rdnss;
+ iov[msg.msg_iovlen].iov_len = ra->rdnss->length * 8;
+ msg.msg_iovlen++;
+ }
+
+ if (ra->dnssl) {
+ iov[msg.msg_iovlen].iov_base = ra->dnssl;
+ iov[msg.msg_iovlen].iov_len = ra->dnssl->length * 8;
+ msg.msg_iovlen++;
+ }
+
if (sendmsg(ra->fd, &msg, 0) < 0)
return -errno;
@@ -545,6 +562,94 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
return 0;
}
+_public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
+ const struct in6_addr *dns, size_t n_dns) {
+ _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
+ size_t len;
+
+ assert_return(ra, -EINVAL);
+ assert_return(n_dns < 128, -EINVAL);
+
+ if (!dns || n_dns == 0) {
+ ra->rdnss = mfree(ra->rdnss);
+ ra->n_rdnss = 0;
+
+ return 0;
+ }
+
+ len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
+
+ opt_rdnss = malloc0(len);
+ if (!opt_rdnss)
+ return -ENOMEM;
+
+ opt_rdnss->type = SD_RADV_OPT_RDNSS;
+ opt_rdnss->length = len / 8;
+ opt_rdnss->lifetime = htobe32(lifetime);
+
+ memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
+
+ free(ra->rdnss);
+ ra->rdnss = opt_rdnss;
+ opt_rdnss = NULL;
+
+ ra->n_rdnss = n_dns;
+
+ return 0;
+}
+
+_public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
+ char **search_list) {
+ _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
+ size_t len = 0;
+ char **s;
+ uint8_t *p;
+
+ assert_return(ra, -EINVAL);
+
+ if (!search_list || *search_list == NULL) {
+ ra->dnssl = mfree(ra->dnssl);
+
+ return 0;
+ }
+
+ STRV_FOREACH(s, search_list)
+ len += strlen(*s) + 2;
+
+ len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
+
+ opt_dnssl = malloc0(len);
+ if (!opt_dnssl)
+ return -ENOMEM;
+
+ opt_dnssl->type = SD_RADV_OPT_DNSSL;
+ opt_dnssl->length = len / 8;
+ opt_dnssl->lifetime = htobe32(lifetime);
+
+ p = (uint8_t *)(opt_dnssl + 1);
+ len -= sizeof(struct sd_radv_opt_dns);
+
+ STRV_FOREACH(s, search_list) {
+ int r;
+
+ r = dns_name_to_wire_format(*s, p, len, false);
+ if (r < 0)
+ return r;
+
+ if (len < (size_t)r)
+ return -ENOBUFS;
+
+ p += r;
+ len -= r;
+ }
+
+ free(ra->dnssl);
+ ra->dnssl = opt_dnssl;
+ opt_dnssl = NULL;
+
+ return 0;
+}
+
_public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index f5f1284e6d..1942199294 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -56,7 +56,8 @@ static void test_request_basic(sd_event *e) {
if (verbose)
printf("* %s\n", __FUNCTION__);
- r = sd_dhcp_client_new(&client);
+ /* Initialize client without Anonymize settings. */
+ r = sd_dhcp_client_new(&client, false);
assert_se(r >= 0);
assert_se(client);
@@ -78,6 +79,8 @@ static void test_request_basic(sd_event *e) {
SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
SD_DHCP_OPTION_ROUTER) == -EEXIST);
+ /* This PRL option is not set when using Anonymize, but in this test
+ * Anonymize settings are not being used. */
assert_se(sd_dhcp_client_set_request_option(client,
SD_DHCP_OPTION_HOST_NAME) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
@@ -97,10 +100,49 @@ static void test_request_basic(sd_event *e) {
SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
== -EINVAL);
- assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
- assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
- assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
- assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
+ /* RFC7844: option 33 (SD_DHCP_OPTION_STATIC_ROUTE) is set in the
+ * default PRL when using Anonymize, so it is changed to other option
+ * that is not set by default, to check that it succed setting it.
+ * Ooptions not set by default (using or not anonymize) are option 17
+ * (SD_DHCP_OPTION_ROOT_PATH) and 42 (SD_DHCP_OPTION_NTP_SERVER) */
+ assert_se(sd_dhcp_client_set_request_option(client, 17) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
+ assert_se(sd_dhcp_client_set_request_option(client, 42) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, 17) == -EEXIST);
+
+ sd_dhcp_client_unref(client);
+}
+
+static void test_request_anonymize(sd_event *e) {
+ int r;
+
+ sd_dhcp_client *client;
+
+ if (verbose)
+ printf("* %s\n", __FUNCTION__);
+
+ /* Initialize client with Anonymize settings. */
+ r = sd_dhcp_client_new(&client, true);
+
+ assert_se(r >= 0);
+ assert_se(client);
+
+ r = sd_dhcp_client_attach_event(client, e, 0);
+ assert_se(r >= 0);
+
+ assert_se(sd_dhcp_client_set_request_option(client,
+ SD_DHCP_OPTION_NETBIOS_NAMESERVER) == -EEXIST);
+ /* This PRL option is not set when using Anonymize */
+ assert_se(sd_dhcp_client_set_request_option(client,
+ SD_DHCP_OPTION_HOST_NAME) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client,
+ SD_DHCP_OPTION_PARAMETER_REQUEST_LIST)
+ == -EINVAL);
+
+ /* RFC7844: option 101 (SD_DHCP_OPTION_NEW_TZDB_TIMEZONE) is not set in the
+ * default PRL when using Anonymize, */
+ assert_se(sd_dhcp_client_set_request_option(client, 101) == 0);
+ assert_se(sd_dhcp_client_set_request_option(client, 101) == -EEXIST);
sd_dhcp_client_unref(client);
}
@@ -236,7 +278,7 @@ static void test_discover_message(sd_event *e) {
if (verbose)
printf("* %s\n", __FUNCTION__);
- r = sd_dhcp_client_new(&client);
+ r = sd_dhcp_client_new(&client, false);
assert_se(r >= 0);
assert_se(client);
@@ -252,7 +294,7 @@ static void test_discover_message(sd_event *e) {
res = sd_dhcp_client_start(client);
- assert_se(res == 0 || res == -EINPROGRESS);
+ assert_se(IN_SET(res, 0, -EINPROGRESS));
sd_event_run(e, (uint64_t) -1);
@@ -451,7 +493,7 @@ static void test_addr_acq(sd_event *e) {
if (verbose)
printf("* %s\n", __FUNCTION__);
- r = sd_dhcp_client_new(&client);
+ r = sd_dhcp_client_new(&client, false);
assert_se(r >= 0);
assert_se(client);
@@ -471,7 +513,7 @@ static void test_addr_acq(sd_event *e) {
test_dhcp_hangcheck, NULL) >= 0);
res = sd_dhcp_client_start(client);
- assert_se(res == 0 || res == -EINPROGRESS);
+ assert_se(IN_SET(res, 0, -EINPROGRESS));
assert_se(sd_event_loop(e) >= 0);
@@ -497,6 +539,7 @@ int main(int argc, char *argv[]) {
assert_se(sd_event_new(&e) >= 0);
test_request_basic(e);
+ test_request_anonymize(e);
test_checksum();
test_discover_message(e);
diff --git a/src/libsystemd-network/test-ndisc-ra.c b/src/libsystemd-network/test-ndisc-ra.c
index 6e6d05642d..18205ef2c9 100644
--- a/src/libsystemd-network/test-ndisc-ra.c
+++ b/src/libsystemd-network/test-ndisc-ra.c
@@ -53,11 +53,11 @@ static uint8_t advertisement[] = {
0x00, 0x09, 0x3a, 0x80, 0x00, 0x00, 0x00, 0x00,
0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x01, 0x0d, 0xad,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Recursive DNS Server Option - not yet supported */
+ /* Recursive DNS Server Option */
0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- /* DNS Search List Option - not yet supported */
+ /* DNS Search List Option */
0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -106,6 +106,13 @@ static struct {
false },
};
+static const struct in6_addr test_rdnss = { { { 0x20, 0x01, 0x0d, 0xb8,
+ 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01 } } };
+static const char *test_dnssl[] = { "lab.intra",
+ NULL };
+
static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
void *userdata) {
assert_se(false);
@@ -207,6 +214,19 @@ static void test_radv(void) {
assert_se(sd_radv_set_other_information(ra, true) >= 0);
assert_se(sd_radv_set_other_information(ra, false) >= 0);
+ assert_se(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
+ assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 0, NULL, 128) < 0);
+ assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 0) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 1) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 0, &test_rdnss, 1) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
+
+ assert_se(sd_radv_set_dnssl(ra, 0, NULL) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 600, NULL) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 0, (char **)test_dnssl) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 600, (char **)test_dnssl) >= 0);
+
ra = sd_radv_unref(ra);
assert_se(!ra);
}
@@ -238,7 +258,7 @@ int icmp6_receive(int fd, void *iov_base, size_t iov_len,
static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
sd_radv *ra = userdata;
- unsigned char buf[120];
+ unsigned char buf[168];
size_t i;
read(test_fd[0], &buf, sizeof(buf));
@@ -254,6 +274,9 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat
/* test only up to buf size, rest is not yet implemented */
for (i = 0; i < sizeof(buf); i++) {
+ if (!(i % 8))
+ printf("%3zd: ", i);
+
printf("0x%02x", buf[i]);
assert_se(buf[i] == advertisement[i]);
@@ -302,6 +325,8 @@ static void test_ra(void) {
assert_se(sd_radv_set_hop_limit(ra, 64) >= 0);
assert_se(sd_radv_set_managed_information(ra, true) >= 0);
assert_se(sd_radv_set_other_information(ra, true) >= 0);
+ assert_se(sd_radv_set_rdnss(ra, 60, &test_rdnss, 1) >= 0);
+ assert_se(sd_radv_set_dnssl(ra, 60, (char **)test_dnssl) >= 0);
for (i = 0; i < ELEMENTSOF(prefix); i++) {
sd_radv_prefix *p;
diff --git a/src/libsystemd/.gitignore b/src/libsystemd/.gitignore
deleted file mode 100644
index 50a1692374..0000000000
--- a/src/libsystemd/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/libsystemd.pc
diff --git a/src/libsystemd/Makefile b/src/libsystemd/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-bus/Makefile b/src/libsystemd/sd-bus/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-bus/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 3191d27ded..9827a42267 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -140,138 +140,3 @@ int bus_container_connect_socket(sd_bus *b) {
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;
-}
diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h
index 509ef45624..35952d9256 100644
--- a/src/libsystemd/sd-bus/bus-container.h
+++ b/src/libsystemd/sd-bus/bus-container.h
@@ -22,4 +22,3 @@
#include "sd-bus.h"
int bus_container_connect_socket(sd_bus *b);
-int bus_container_connect_kernel(sd_bus *b);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index b56bb07713..fcd4d27e07 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_VALGRIND_MEMCHECK_H
+#if HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
@@ -56,38 +56,6 @@ _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
return 0;
}
-static 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);
-
-#ifdef 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;
-}
-
static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
uint32_t ret, param = 0;
@@ -151,37 +119,7 @@ _public_ int sd_bus_request_name(sd_bus *bus, const char *name, uint64_t flags)
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- if (bus->is_kernel)
- return bus_request_name_kernel(bus, name, flags);
- else
- return bus_request_name_dbus1(bus, name, flags);
-}
-
-static 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);
-
-#ifdef 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;
+ return bus_request_name_dbus1(bus, name, flags);
}
static int bus_release_name_dbus1(sd_bus *bus, const char *name) {
@@ -235,95 +173,7 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- if (bus->is_kernel)
- return bus_release_name_kernel(bus, name);
- else
- return bus_release_name_dbus1(bus, name);
-}
-
-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;
-}
-
-static 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;
+ return bus_release_name_dbus1(bus, name);
}
static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) {
@@ -391,365 +241,7 @@ _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatabl
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
- if (bus->is_kernel)
- return bus_list_names_kernel(bus, acquired, activatable);
- else
- return bus_list_names_dbus1(bus, acquired, activatable);
-}
-
-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;
-}
-
-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;
+ return bus_list_names_dbus1(bus, acquired, activatable);
}
static int bus_get_name_creds_dbus1(
@@ -1056,60 +548,7 @@ _public_ int sd_bus_get_name_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;
+ return bus_get_name_creds_dbus1(bus, name, mask, creds);
}
static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
@@ -1176,398 +615,7 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
if (!bus->is_local)
mask &= ~SD_BUS_CREDS_AUGMENT;
- if (bus->is_kernel)
- return bus_get_owner_creds_kdbus(bus, mask, ret);
- else
- return bus_get_owner_creds_dbus1(bus, mask, ret);
-}
-
-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;
+ return bus_get_owner_creds_dbus1(bus, mask, ret);
}
#define internal_match(bus, m) \
@@ -1602,41 +650,14 @@ int bus_add_match_internal(
sd_bus *bus,
const char *match,
struct bus_match_component *components,
- unsigned n_components,
- uint64_t cookie) {
+ unsigned n_components) {
assert(bus);
if (!bus->bus_client)
return -EINVAL;
- if (bus->is_kernel)
- return bus_add_match_internal_kernel(bus, components, n_components, cookie);
- else
- return bus_add_match_internal_dbus1(bus, match);
-}
-
-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;
+ return bus_add_match_internal_dbus1(bus, match);
}
static int bus_remove_match_internal_dbus1(
@@ -1664,18 +685,14 @@ static int bus_remove_match_internal_dbus1(
int bus_remove_match_internal(
sd_bus *bus,
- const char *match,
- uint64_t cookie) {
+ const char *match) {
assert(bus);
if (!bus->bus_client)
return -EINVAL;
- if (bus->is_kernel)
- return bus_remove_match_internal_kernel(bus, cookie);
- else
- return bus_remove_match_internal_dbus1(bus, match);
+ return bus_remove_match_internal_dbus1(bus, match);
}
_public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) {
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index c181aa7959..01c71874db 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -23,10 +23,5 @@
#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_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);
+int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components);
+int bus_remove_match_internal(sd_bus *bus, const char *match);
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 04158cae4d..e171c53e21 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -533,19 +533,12 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
* to get it from the sender or peer. */
if (call->sender)
- /* There's a sender, but the creds are
- * missing. This means we are talking via
- * dbus1, or are getting a message that was
- * sent to us via kdbus, but was converted
- * from a dbus1 message by the bus-proxy and
- * thus also lacks the creds. */
+ /* There's a sender, but the creds are missing. */
return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
else
- /* There's no sender, hence we are on a dbus1
- * direct connection. For direct connections
+ /* There's no sender. For direct connections
* the credentials of the AF_UNIX peer matter,
- * which may be queried via
- * sd_bus_get_owner_creds(). */
+ * which may be queried via sd_bus_get_owner_creds(). */
return sd_bus_get_owner_creds(call->bus, mask, creds);
}
@@ -579,9 +572,6 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
* here. */
assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
- /* Note that not even on kdbus we might have the caps
- * field, due to faked identities, or namespace
- * translation issues. */
r = sd_bus_creds_has_effective_cap(creds, capability);
if (r > 0)
return 1;
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index 349fa57f2d..21a15c8d60 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -165,7 +165,7 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m
assert_return(ret, -EINVAL);
if (pid == 0)
- pid = getpid();
+ pid = getpid_cached();
c = bus_creds_new();
if (!c)
@@ -570,7 +570,7 @@ _public_ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessio
if (!(c->mask & SD_BUS_CREDS_AUDIT_SESSION_ID))
return -ENODATA;
- if (c->audit_session_id == AUDIT_SESSION_INVALID)
+ if (!audit_session_is_valid(c->audit_session_id))
return -ENXIO;
*sessionid = c->audit_session_id;
@@ -584,7 +584,7 @@ _public_ int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *uid) {
if (!(c->mask & SD_BUS_CREDS_AUDIT_LOGIN_UID))
return -ENODATA;
- if (c->audit_login_uid == UID_INVALID)
+ if (!uid_is_valid(c->audit_login_uid))
return -ENXIO;
*uid = c->audit_login_uid;
@@ -816,7 +816,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (!f) {
if (errno == ENOENT)
return -ESRCH;
- else if (errno != EPERM && errno != EACCES)
+ else if (!IN_SET(errno, EPERM, EACCES))
return -errno;
} else {
char line[LINE_MAX];
@@ -974,7 +974,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
p = procfs_file_alloca(pid, "attr/current");
r = read_one_line_file(p, &c->label);
if (r < 0) {
- if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
@@ -983,7 +983,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_COMM) {
r = get_process_comm(pid, &c->comm);
if (r < 0) {
- if (r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_COMM;
@@ -1002,7 +1002,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->exe = NULL;
c->mask |= SD_BUS_CREDS_EXE;
} else if (r < 0) {
- if (r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_EXE;
@@ -1016,7 +1016,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (r == -ENOENT)
return -ESRCH;
if (r < 0) {
- if (r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EPERM, -EACCES))
return r;
} else {
if (c->cmdline_size == 0)
@@ -1036,7 +1036,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (r == -ENOENT)
return -ESRCH;
if (r < 0) {
- if (r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_TID_COMM;
@@ -1047,7 +1047,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (!c->cgroup) {
r = cg_pid_get_path(NULL, pid, &c->cgroup);
if (r < 0) {
- if (r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EPERM, -EACCES))
return r;
}
}
@@ -1069,7 +1069,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->audit_session_id = AUDIT_SESSION_INVALID;
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
} else if (r < 0) {
- if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
@@ -1082,7 +1082,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->audit_login_uid = UID_INVALID;
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
} else if (r < 0) {
- if (r != -EOPNOTSUPP && r != -ENOENT && r != -EPERM && r != -EACCES)
+ if (!IN_SET(r, -EOPNOTSUPP, -ENOENT, -EPERM, -EACCES))
return r;
} else
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
@@ -1095,7 +1095,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->tty = NULL;
c->mask |= SD_BUS_CREDS_TTY;
} else if (r < 0) {
- if (r != -EPERM && r != -EACCES && r != -ENOENT)
+ if (!IN_SET(r, -EPERM, -EACCES, -ENOENT))
return r;
} else
c->mask |= SD_BUS_CREDS_TTY;
diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c
index caca679086..dacd243c3e 100644
--- a/src/libsystemd/sd-bus/bus-internal.c
+++ b/src/libsystemd/sd-bus/bus-internal.c
@@ -148,7 +148,7 @@ bool service_name_is_valid(const char *p) {
(*q >= 'a' && *q <= 'z') ||
(*q >= 'A' && *q <= 'Z') ||
((!dot || unique) && *q >= '0' && *q <= '9') ||
- *q == '_' || *q == '-';
+ IN_SET(*q, '_', '-');
if (!good)
return false;
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index ad4b4a09b2..90dee1b926 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -28,6 +28,7 @@
#include "bus-error.h"
#include "bus-kernel.h"
#include "bus-match.h"
+#include "def.h"
#include "hashmap.h"
#include "list.h"
#include "prioq.h"
@@ -53,7 +54,6 @@ struct filter_callback {
struct match_callback {
sd_bus_message_handler_t callback;
- uint64_t cookie;
unsigned last_iteration;
char *match_string;
@@ -191,7 +191,6 @@ struct sd_bus {
int message_version;
int message_endian;
- bool is_kernel:1;
bool can_fds:1;
bool bus_client:1;
bool ucred_valid:1;
@@ -203,8 +202,6 @@ struct sd_bus {
bool filter_callbacks_modified:1;
bool nodes_modified:1;
bool trusted:1;
- bool fake_creds_valid:1;
- bool fake_pids_valid:1;
bool manual_peer_interface:1;
bool is_system:1;
bool is_user:1;
@@ -245,7 +242,6 @@ struct sd_bus {
union sockaddr_union sockaddr;
socklen_t sockaddr_size;
- char *kernel;
char *machine;
pid_t nspid;
@@ -276,8 +272,6 @@ struct sd_bus {
unsigned iteration_counter;
- void *kdbus_buffer;
-
/* We do locking around the memfd cache, since we want to
* allow people to process a sd_bus_message in a different
* thread then it was generated on and free it there. Since
@@ -293,8 +287,6 @@ struct sd_bus {
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;
@@ -310,25 +302,23 @@ struct sd_bus {
sd_bus **default_bus_ptr;
pid_t tid;
- struct kdbus_creds fake_creds;
- struct kdbus_pids fake_pids;
- char *fake_label;
-
char *cgroup_root;
char *description;
- size_t bloom_size;
- unsigned bloom_n_hash;
-
sd_bus_track *track_queue;
LIST_HEAD(sd_bus_slot, slots);
LIST_HEAD(sd_bus_track, tracks);
};
+/* For method calls we time-out at 25s, like in the D-Bus reference implementation */
#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
+/* For the authentication phase we grant 90s, to provide extra room during boot, when RNGs and such are not filled up
+ * with enough entropy yet and might delay the boot */
+#define BUS_AUTH_TIMEOUT ((usec_t) DEFAULT_TIMEOUT_USEC)
+
#define BUS_WQUEUE_MAX (192*1024)
#define BUS_RQUEUE_MAX (192*1024)
@@ -402,3 +392,65 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
if (!assert_log(expr, #expr)) \
return sd_bus_error_set_errno(error, r); \
} while (false)
+
+/**
+ * enum kdbus_attach_flags - flags for metadata attachments
+ * @KDBUS_ATTACH_TIMESTAMP: Timestamp
+ * @KDBUS_ATTACH_CREDS: Credentials
+ * @KDBUS_ATTACH_PIDS: PIDs
+ * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups
+ * @KDBUS_ATTACH_NAMES: Well-known names
+ * @KDBUS_ATTACH_TID_COMM: The "comm" process identifier of the TID
+ * @KDBUS_ATTACH_PID_COMM: The "comm" process identifier of the PID
+ * @KDBUS_ATTACH_EXE: The path of the executable
+ * @KDBUS_ATTACH_CMDLINE: The process command line
+ * @KDBUS_ATTACH_CGROUP: The croup membership
+ * @KDBUS_ATTACH_CAPS: The process capabilities
+ * @KDBUS_ATTACH_SECLABEL: The security label
+ * @KDBUS_ATTACH_AUDIT: The audit IDs
+ * @KDBUS_ATTACH_CONN_DESCRIPTION: The human-readable connection name
+ * @_KDBUS_ATTACH_ALL: All of the above
+ * @_KDBUS_ATTACH_ANY: Wildcard match to enable any kind of
+ * metatdata.
+ */
+enum kdbus_attach_flags {
+ KDBUS_ATTACH_TIMESTAMP = 1ULL << 0,
+ KDBUS_ATTACH_CREDS = 1ULL << 1,
+ KDBUS_ATTACH_PIDS = 1ULL << 2,
+ KDBUS_ATTACH_AUXGROUPS = 1ULL << 3,
+ KDBUS_ATTACH_NAMES = 1ULL << 4,
+ KDBUS_ATTACH_TID_COMM = 1ULL << 5,
+ KDBUS_ATTACH_PID_COMM = 1ULL << 6,
+ KDBUS_ATTACH_EXE = 1ULL << 7,
+ KDBUS_ATTACH_CMDLINE = 1ULL << 8,
+ KDBUS_ATTACH_CGROUP = 1ULL << 9,
+ KDBUS_ATTACH_CAPS = 1ULL << 10,
+ KDBUS_ATTACH_SECLABEL = 1ULL << 11,
+ KDBUS_ATTACH_AUDIT = 1ULL << 12,
+ KDBUS_ATTACH_CONN_DESCRIPTION = 1ULL << 13,
+ _KDBUS_ATTACH_ALL = (1ULL << 14) - 1,
+ _KDBUS_ATTACH_ANY = ~0ULL
+};
+
+/**
+ * enum kdbus_hello_flags - flags for struct kdbus_cmd_hello
+ * @KDBUS_HELLO_ACCEPT_FD: The connection allows the reception of
+ * any passed file descriptors
+ * @KDBUS_HELLO_ACTIVATOR: Special-purpose connection which registers
+ * a well-know name for a process to be started
+ * when traffic arrives
+ * @KDBUS_HELLO_POLICY_HOLDER: Special-purpose connection which registers
+ * policy entries for a name. The provided name
+ * is not activated and not registered with the
+ * name database, it only allows unprivileged
+ * connections to acquire a name, talk or discover
+ * a service
+ * @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor
+ * bus traffic
+ */
+enum kdbus_hello_flags {
+ KDBUS_HELLO_ACCEPT_FD = 1ULL << 0,
+ KDBUS_HELLO_ACTIVATOR = 1ULL << 1,
+ KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2,
+ KDBUS_HELLO_MONITOR = 1ULL << 3,
+};
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
index 8f93edb8da..9fcb59631c 100644
--- a/src/libsystemd/sd-bus/bus-introspect.c
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -36,8 +36,8 @@ int introspect_begin(struct introspect *i, bool trusted) {
if (!i->f)
return -ENOMEM;
- fputs(BUS_INTROSPECT_DOCTYPE
- "<node>\n", i->f);
+ fputs_unlocked(BUS_INTROSPECT_DOCTYPE
+ "<node>\n", i->f);
return 0;
}
@@ -45,12 +45,12 @@ int introspect_begin(struct introspect *i, bool trusted) {
int introspect_write_default_interfaces(struct introspect *i, bool object_manager) {
assert(i);
- fputs(BUS_INTROSPECT_INTERFACE_PEER
- BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
- BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
+ fputs_unlocked(BUS_INTROSPECT_INTERFACE_PEER
+ BUS_INTROSPECT_INTERFACE_INTROSPECTABLE
+ BUS_INTROSPECT_INTERFACE_PROPERTIES, i->f);
if (object_manager)
- fputs(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
+ fputs_unlocked(BUS_INTROSPECT_INTERFACE_OBJECT_MANAGER, i->f);
return 0;
}
@@ -76,27 +76,27 @@ int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefi
static void introspect_write_flags(struct introspect *i, int type, int flags) {
if (flags & SD_BUS_VTABLE_DEPRECATED)
- fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
if (type == _SD_BUS_VTABLE_METHOD && (flags & SD_BUS_VTABLE_METHOD_NO_REPLY))
- fputs(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n", i->f);
- if (type == _SD_BUS_VTABLE_PROPERTY || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) {
+ if (IN_SET(type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY)) {
if (flags & SD_BUS_VTABLE_PROPERTY_EXPLICIT)
- fputs(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.systemd1.Explicit\" value=\"true\"/>\n", i->f);
if (flags & SD_BUS_VTABLE_PROPERTY_CONST)
- fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"const\"/>\n", i->f);
else if (flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)
- fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"invalidates\"/>\n", i->f);
else if (!(flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE))
- fputs(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Property.EmitsChangedSignal\" value=\"false\"/>\n", i->f);
}
if (!i->trusted &&
- (type == _SD_BUS_VTABLE_METHOD || type == _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
+ IN_SET(type, _SD_BUS_VTABLE_METHOD, _SD_BUS_VTABLE_WRITABLE_PROPERTY) &&
!(flags & SD_BUS_VTABLE_UNPRIVILEGED))
- fputs(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
}
static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
@@ -117,7 +117,7 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
if (direction)
fprintf(i->f, " direction=\"%s\"/>\n", direction);
else
- fputs("/>\n", i->f);
+ fputs_unlocked("/>\n", i->f);
signature += l;
}
@@ -140,7 +140,7 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
case _SD_BUS_VTABLE_START:
if (v->flags & SD_BUS_VTABLE_DEPRECATED)
- fputs(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
+ fputs_unlocked(" <annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n", i->f);
break;
case _SD_BUS_VTABLE_METHOD:
@@ -148,7 +148,7 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
introspect_write_arguments(i, strempty(v->x.method.signature), "in");
introspect_write_arguments(i, strempty(v->x.method.result), "out");
introspect_write_flags(i, v->type, v->flags);
- fputs(" </method>\n", i->f);
+ fputs_unlocked(" </method>\n", i->f);
break;
case _SD_BUS_VTABLE_PROPERTY:
@@ -158,14 +158,14 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
v->x.property.signature,
v->type == _SD_BUS_VTABLE_WRITABLE_PROPERTY ? "readwrite" : "read");
introspect_write_flags(i, v->type, v->flags);
- fputs(" </property>\n", i->f);
+ fputs_unlocked(" </property>\n", i->f);
break;
case _SD_BUS_VTABLE_SIGNAL:
fprintf(i->f, " <signal name=\"%s\">\n", v->x.signal.member);
introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
introspect_write_flags(i, v->type, v->flags);
- fputs(" </signal>\n", i->f);
+ fputs_unlocked(" </signal>\n", i->f);
break;
}
@@ -182,7 +182,7 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b
assert(m);
assert(reply);
- fputs("</node>\n", i->f);
+ fputs_unlocked("</node>\n", i->f);
r = fflush_and_check(i->f);
if (r < 0)
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index ca6aee7c06..5a3c4d6f50 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_VALGRIND_MEMCHECK_H
+#if HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
@@ -33,7 +33,6 @@
#undef basename
#include "alloc-util.h"
-#include "bus-bloom.h"
#include "bus-internal.h"
#include "bus-kernel.h"
#include "bus-label.h"
@@ -51,1471 +50,14 @@
#include "user-util.h"
#include "util.h"
-#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);
-
- strcpy(e, "-dot-prefix");
- bloom_add_prefixes(data, size, n_hash, buf, t, '.');
- strcpy(e, "-slash-prefix");
- 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);
-}
-
-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));
-
- 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;
-
- 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;
-
- 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;
- }
-
- 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;
- }
-
- /* 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->attach_flags_send = _KDBUS_ATTACH_ANY;
- 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;
- }
-
- 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) {
+void close_and_munmap(int fd, void *address, size_t size) {
if (size > 0)
assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
safe_close(fd);
}
-void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) {
- struct memfd_cache *c;
- uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
-
- assert(fd >= 0);
- assert(mapped == 0 || address);
-
- if (!bus || !bus->is_kernel) {
- close_and_munmap(fd, address, mapped);
- return;
- }
-
- assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
-
- if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
-
- close_and_munmap(fd, address, mapped);
- return;
- }
-
- c = &bus->memfd_cache[bus->n_memfd_cache++];
- c->fd = fd;
- c->address = address;
-
- /* If overly long, let's return a bit to the OS */
- if (mapped > max_mapped) {
- assert_se(memfd_set_size(fd, max_mapped) >= 0);
- assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0);
- c->mapped = c->allocated = max_mapped;
- } else {
- c->mapped = mapped;
- c->allocated = allocated;
- }
-
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
-}
-
-void bus_kernel_flush_memfd(sd_bus *b) {
+void bus_flush_memfd(sd_bus *b) {
unsigned i;
assert(b);
@@ -1524,21 +66,6 @@ void bus_kernel_flush_memfd(sd_bus *b) {
close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
}
-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;
-}
-
uint64_t attach_flags_to_kdbus(uint64_t mask) {
uint64_t m = 0;
@@ -1584,199 +111,3 @@ uint64_t attach_flags_to_kdbus(uint64_t mask) {
return m;
}
-
-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;
- n->bloom_parameter.size = DEFAULT_BLOOM_SIZE;
- n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH;
-
- 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;
-}
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index 53ba3bdcf3..49c0ab3a3c 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -19,27 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-
#include "sd-bus.h"
-#define KDBUS_ITEM_NEXT(item) \
- (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
-
-#define KDBUS_ITEM_FOREACH(part, head, first) \
- for (part = (head)->first; \
- ((uint8_t *)(part) < (uint8_t *)(head) + (head)->size) && \
- ((uint8_t *) part >= (uint8_t *) head); \
- part = KDBUS_ITEM_NEXT(part))
-#define KDBUS_FOREACH(iter, first, _size) \
- for (iter = (first); \
- ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \
- ((uint8_t *)(iter) >= (uint8_t *)(first)); \
- iter = (void*)(((uint8_t *)iter) + ALIGN8((iter)->size)))
-
-#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
-#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
-
#define MEMFD_CACHE_MAX 32
/* When we cache a memfd block for reuse, we will truncate blocks
@@ -50,10 +31,6 @@
* sending vectors */
#define MEMFD_MIN_SIZE (512*1024)
-/* The size of the per-connection memory pool that we set up and where
- * the kernel places our incoming messages */
-#define KDBUS_POOL_SIZE (16*1024*1024)
-
struct memfd_cache {
int fd;
void *address;
@@ -61,33 +38,7 @@ struct memfd_cache {
size_t allocated;
};
-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);
+void close_and_munmap(int fd, void *address, size_t size);
+void bus_flush_memfd(sd_bus *bus);
-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);
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index db01f21135..a972c13054 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -453,7 +453,7 @@ static int bus_match_add_compare_value(
int r;
assert(where);
- assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+ assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
assert(BUS_MATCH_IS_COMPARE(t));
assert(ret);
@@ -567,7 +567,7 @@ static int bus_match_find_compare_value(
struct bus_match_node *c, *n;
assert(where);
- assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+ assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
assert(BUS_MATCH_IS_COMPARE(t));
assert(ret);
@@ -601,7 +601,7 @@ static int bus_match_add_leaf(
struct bus_match_node *n;
assert(where);
- assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+ assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
assert(callback);
n = new0(struct bus_match_node, 1);
@@ -631,7 +631,7 @@ static int bus_match_find_leaf(
struct bus_match_node *c;
assert(where);
- assert(where->type == BUS_MATCH_ROOT || where->type == BUS_MATCH_VALUE);
+ assert(IN_SET(where->type, BUS_MATCH_ROOT, BUS_MATCH_VALUE));
assert(ret);
for (c = where->child; c; c = c->next) {
@@ -957,18 +957,18 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com
char buf[32];
if (i != 0)
- fputc(',', f);
+ fputc_unlocked(',', f);
- fputs(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
- fputc('=', f);
- fputc('\'', f);
+ fputs_unlocked(bus_match_node_type_to_string(components[i].type, buf, sizeof(buf)), f);
+ fputc_unlocked('=', f);
+ fputc_unlocked('\'', f);
if (components[i].type == BUS_MATCH_MESSAGE_TYPE)
- fputs(bus_message_type_to_string(components[i].value_u8), f);
+ fputs_unlocked(bus_message_type_to_string(components[i].value_u8), f);
else
- fputs(components[i].value_str, f);
+ fputs_unlocked(components[i].value_str, f);
- fputc('\'', f);
+ fputc_unlocked('\'', f);
}
r = fflush_and_check(f);
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index da6fd3b896..3fc447df3f 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -62,22 +62,9 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
assert(m);
assert(part);
- if (part->memfd >= 0) {
- /* If we can reuse the memfd, try that. For that it
- * can't be sealed yet. */
-
- if (!part->sealed) {
- assert(part->memfd_offset == 0);
- assert(part->data == part->mmap_begin);
- bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
- } else {
- if (part->mapped > 0)
- assert_se(munmap(part->mmap_begin, part->mapped) == 0);
-
- safe_close(part->memfd);
- }
-
- } else if (part->munmap_this)
+ if (part->memfd >= 0)
+ close_and_munmap(part->memfd, part->mmap_begin, part->mapped);
+ else if (part->munmap_this)
munmap(part->mmap_begin, part->mapped);
else if (part->free_this)
free(part->data);
@@ -129,12 +116,6 @@ static void message_free(sd_bus_message *m) {
message_reset_parts(m);
- if (m->release_kdbus)
- bus_kernel_cmd_free(m->bus, (uint8_t *) m->kdbus - (uint8_t *) m->bus->kdbus_buffer);
-
- if (m->free_kdbus)
- free(m->kdbus);
-
sd_bus_unref(m->bus);
if (m->free_fds) {
@@ -606,7 +587,7 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
m->header->endian = BUS_NATIVE_ENDIAN;
m->header->type = type;
m->header->version = bus->message_version;
- m->allow_fds = bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
+ m->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
m->bus = sd_bus_ref(bus);
@@ -1215,7 +1196,6 @@ static int part_make_space(
void **q) {
void *n;
- int r;
assert(m);
assert(part);
@@ -1224,61 +1204,19 @@ static int part_make_space(
if (m->poisoned)
return -ENOMEM;
- if (!part->data && part->memfd < 0) {
- part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
- part->mmap_begin = part->data;
- }
-
- if (part->memfd >= 0) {
-
- if (part->allocated == 0 || sz > part->allocated) {
- uint64_t new_allocated;
-
- new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
- r = memfd_set_size(part->memfd, new_allocated);
- if (r < 0) {
- m->poisoned = true;
- return r;
- }
-
- part->allocated = new_allocated;
- }
-
- if (!part->data || sz > part->mapped) {
- size_t psz;
-
- psz = PAGE_ALIGN(sz > 0 ? sz : 1);
- if (part->mapped <= 0)
- n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
- else
- n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE);
+ if (part->allocated == 0 || sz > part->allocated) {
+ size_t new_allocated;
- if (n == MAP_FAILED) {
- m->poisoned = true;
- return -errno;
- }
-
- part->mmap_begin = part->data = n;
- part->mapped = psz;
- part->memfd_offset = 0;
+ new_allocated = sz > 0 ? 2 * sz : 64;
+ n = realloc(part->data, new_allocated);
+ if (!n) {
+ m->poisoned = true;
+ return -ENOMEM;
}
- part->munmap_this = true;
- } else {
- if (part->allocated == 0 || sz > part->allocated) {
- size_t new_allocated;
-
- new_allocated = sz > 0 ? 2 * sz : 64;
- n = realloc(part->data, new_allocated);
- if (!n) {
- m->poisoned = true;
- return -ENOMEM;
- }
-
- part->data = n;
- part->allocated = new_allocated;
- part->free_this = true;
- }
+ part->data = n;
+ part->allocated = new_allocated;
+ part->free_this = true;
}
if (q)
@@ -1612,7 +1550,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void
if (!a)
return -ENOMEM;
- if (type == SD_BUS_TYPE_STRING || type == SD_BUS_TYPE_OBJECT_PATH) {
+ if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
*(uint32_t*) a = sz - 5;
memcpy((uint8_t*) a + 4, p, sz - 4);
@@ -2291,7 +2229,7 @@ _public_ int sd_bus_message_close_container(sd_bus_message *m) {
r = bus_message_close_array(m, c);
else if (c->enclosing == SD_BUS_TYPE_VARIANT)
r = bus_message_close_variant(m, c);
- else if (c->enclosing == SD_BUS_TYPE_STRUCT || c->enclosing == SD_BUS_TYPE_DICT_ENTRY)
+ else if (IN_SET(c->enclosing, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY))
r = bus_message_close_struct(m, c, true);
else
assert_not_reached("Unknown container type");
@@ -3233,9 +3171,7 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
c->offset_index++;
- } else if (c->enclosing == 0 ||
- c->enclosing == SD_BUS_TYPE_STRUCT ||
- c->enclosing == SD_BUS_TYPE_DICT_ENTRY) {
+ } else if (IN_SET(c->enclosing, 0, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
int alignment;
size_t n, j;
@@ -4283,8 +4219,7 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
return 1;
}
- if (c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ||
- c->signature[c->index] == SD_BUS_TYPE_DICT_ENTRY_BEGIN) {
+ if (IN_SET(c->signature[c->index], SD_BUS_TYPE_STRUCT_BEGIN, SD_BUS_TYPE_DICT_ENTRY_BEGIN)) {
if (contents) {
size_t l;
@@ -5122,8 +5057,7 @@ static int message_skip_fields(
(*signature)++;
- } else if (t == SD_BUS_TYPE_STRUCT ||
- t == SD_BUS_TYPE_DICT_ENTRY) {
+ } else if (IN_SET(t, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
r = signature_element_length(*signature, &l);
if (r < 0)
@@ -5368,7 +5302,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
- if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client && !m->bus->is_kernel) {
+ if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client) {
m->creds.unique_name = (char*) m->sender;
m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
}
@@ -5781,9 +5715,7 @@ _public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int
assert(r > 0);
- if (type == SD_BUS_TYPE_OBJECT_PATH ||
- type == SD_BUS_TYPE_SIGNATURE ||
- type == SD_BUS_TYPE_STRING)
+ if (IN_SET(type, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE, SD_BUS_TYPE_STRING))
r = sd_bus_message_append_basic(m, type, basic.string);
else
r = sd_bus_message_append_basic(m, type, &basic);
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index a59aa73833..a84f908f75 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -92,9 +92,7 @@ struct sd_bus_message {
bool dont_send:1;
bool allow_fds:1;
bool free_header:1;
- bool free_kdbus:1;
bool free_fds:1;
- bool release_kdbus:1;
bool poisoned:1;
/* The first and last bytes of the message */
@@ -128,8 +126,6 @@ struct sd_bus_message {
struct iovec iovec_fixed[2];
unsigned n_iovec;
- struct kdbus_msg *kdbus;
-
char *peeked_signature;
/* If set replies to this message must carry the signature
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 98911d5203..df2bdc806c 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -38,7 +38,7 @@ static int node_vtable_get_userdata(
sd_bus_error *error) {
sd_bus_slot *s;
- void *u;
+ void *u, *found_u;
int r;
assert(bus);
@@ -50,7 +50,7 @@ static int node_vtable_get_userdata(
if (c->find) {
bus->current_slot = sd_bus_slot_ref(s);
bus->current_userdata = u;
- r = c->find(bus, path, c->interface, u, &u, error);
+ r = c->find(bus, path, c->interface, u, &found_u, error);
bus->current_userdata = NULL;
bus->current_slot = sd_bus_slot_unref(s);
@@ -60,10 +60,11 @@ static int node_vtable_get_userdata(
return -sd_bus_error_get_errno(error);
if (r == 0)
return r;
- }
+ } else
+ found_u = u;
if (userdata)
- *userdata = u;
+ *userdata = found_u;
return 1;
}
@@ -752,7 +753,7 @@ static int vtable_append_all_properties(
return 1;
for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
- if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+ if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
continue;
if (v->flags & SD_BUS_VTABLE_HIDDEN)
@@ -829,6 +830,9 @@ static int property_get_all_callbacks_run(
return 0;
}
+ if (!*found_object)
+ return 0;
+
if (!found_interface) {
r = sd_bus_reply_method_errorf(
m,
@@ -955,7 +959,7 @@ static int process_introspect(
if (!streq_ptr(previous_interface, c->interface)) {
if (previous_interface)
- fputs(" </interface>\n", intro.f);
+ fputs_unlocked(" </interface>\n", intro.f);
fprintf(intro.f, " <interface name=\"%s\">\n", c->interface);
}
@@ -968,7 +972,7 @@ static int process_introspect(
}
if (previous_interface)
- fputs(" </interface>\n", intro.f);
+ fputs_unlocked(" </interface>\n", intro.f);
if (empty) {
/* Nothing?, let's see if we exist at all, and if not
@@ -1996,7 +2000,7 @@ static int emit_properties_changed_on_interface(
* as changing in the message. */
for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
- if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+ if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
continue;
if (v->flags & SD_BUS_VTABLE_HIDDEN)
@@ -2067,7 +2071,7 @@ static int emit_properties_changed_on_interface(
const sd_bus_vtable *v;
for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
- if (v->type != _SD_BUS_VTABLE_PROPERTY && v->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
+ if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
continue;
if (v->flags & SD_BUS_VTABLE_HIDDEN)
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index 33590c31ac..725265b331 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -93,7 +93,7 @@ void bus_slot_disconnect(sd_bus_slot *slot) {
case BUS_MATCH_CALLBACK:
if (slot->match_added)
- bus_remove_match_internal(slot->bus, slot->match_callback.match_string, slot->match_callback.cookie);
+ bus_remove_match_internal(slot->bus, slot->match_callback.match_string);
slot->bus->match_callbacks_modified = true;
bus_match_remove(&slot->bus->match_callbacks, &slot->match_callback);
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 8b25002f01..235fe26393 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -343,7 +343,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) {
assert(t);
/* We only make use of the first iovec */
- assert(b->auth_index == 0 || b->auth_index == 1);
+ assert(IN_SET(b->auth_index, 0, 1));
l = strlen(t);
p = malloc(b->auth_iovec[0].iov_len + l);
@@ -593,7 +593,6 @@ void bus_socket_setup(sd_bus *b) {
fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
fd_inc_sndbuf(b->output_fd, SNDBUF_SIZE);
- b->is_kernel = false;
b->message_version = 1;
b->message_endian = 0;
}
@@ -661,7 +660,7 @@ int bus_socket_start_auth(sd_bus *b) {
bus_get_peercred(b);
b->state = BUS_AUTHENTICATING;
- b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT;
+ b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_AUTH_TIMEOUT;
if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0)
b->hello_flags &= ~KDBUS_HELLO_ACCEPT_FD;
@@ -732,7 +731,7 @@ int bus_socket_exec(sd_bus *b) {
assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
- if (s[1] != STDIN_FILENO && s[1] != STDOUT_FILENO)
+ if (!IN_SET(s[1], STDIN_FILENO, STDOUT_FILENO))
safe_close(s[1]);
fd_cloexec(STDIN_FILENO, false);
@@ -776,7 +775,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
assert(bus);
assert(m);
assert(idx);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
if (*idx >= BUS_MESSAGE_SIZE(m))
return 0;
@@ -800,7 +799,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
.msg_iovlen = m->n_iovec,
};
- if (m->n_fds > 0) {
+ if (m->n_fds > 0 && *idx == 0) {
struct cmsghdr *control;
mh.msg_control = control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds));
@@ -831,7 +830,7 @@ static int bus_socket_read_message_need(sd_bus *bus, size_t *need) {
assert(bus);
assert(need);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
if (bus->rbuffer_size < sizeof(struct bus_header)) {
*need = sizeof(struct bus_header) + 8;
@@ -883,7 +882,7 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
assert(bus);
assert(bus->rbuffer_size >= size);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
r = bus_rqueue_make_room(bus);
if (r < 0)
@@ -932,7 +931,7 @@ int bus_socket_read_message(sd_bus *bus) {
bool handle_cmsg = false;
assert(bus);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
r = bus_socket_read_message_need(bus, &need);
if (r < 0)
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 2f065c2657..621fabb015 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -56,7 +56,7 @@
#define log_debug_bus_message(m) \
do { \
sd_bus_message *_mm = (m); \
- log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error=%s", \
+ log_debug("Got message type=%s sender=%s destination=%s object=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " error-name=%s error-message=%s", \
bus_message_type_to_string(_mm->header->type), \
strna(sd_bus_message_get_sender(_mm)), \
strna(sd_bus_message_get_destination(_mm)), \
@@ -65,6 +65,7 @@
strna(sd_bus_message_get_member(_mm)), \
BUS_MESSAGE_COOKIE(_mm), \
_mm->reply_cookie, \
+ strna(_mm->error.name), \
strna(_mm->error.message)); \
} while (false)
@@ -131,17 +132,12 @@ static void bus_free(sd_bus *b) {
bus_close_fds(b);
- if (b->kdbus_buffer)
- munmap(b->kdbus_buffer, KDBUS_POOL_SIZE);
-
free(b->label);
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);
@@ -165,7 +161,7 @@ static void bus_free(sd_bus *b) {
assert(hashmap_isempty(b->nodes));
hashmap_free(b->nodes);
- bus_kernel_flush_memfd(b);
+ bus_flush_memfd(b);
assert_se(pthread_mutex_destroy(&b->memfd_cache_mutex) == 0);
@@ -187,7 +183,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
r->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
r->hello_flags |= KDBUS_HELLO_ACCEPT_FD;
r->attach_flags |= KDBUS_ATTACH_NAMES;
- r->original_pid = getpid();
+ r->original_pid = getpid_cached();
assert_se(pthread_mutex_init(&r->memfd_cache_mutex, NULL) == 0);
@@ -300,8 +296,6 @@ _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
return 0;
bus->attach_flags = new_flags;
- if (bus->state != BUS_UNSET && bus->is_kernel)
- bus_kernel_realize_attach_flags(bus);
return 0;
}
@@ -325,8 +319,6 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
return 0;
bus->attach_flags = new_flags;
- if (bus->state != BUS_UNSET && bus->is_kernel)
- bus_kernel_realize_attach_flags(bus);
return 0;
}
@@ -391,7 +383,7 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e
assert(reply);
bus = reply->bus;
assert(bus);
- assert(bus->state == BUS_HELLO || bus->state == BUS_CLOSING);
+ assert(IN_SET(bus->state, BUS_HELLO, BUS_CLOSING));
r = sd_bus_message_get_errno(reply);
if (r > 0)
@@ -420,7 +412,7 @@ static int bus_send_hello(sd_bus *bus) {
assert(bus);
- if (!bus->bus_client || bus->is_kernel)
+ if (!bus->bus_client)
return 0;
r = sd_bus_message_new_method_call(
@@ -439,7 +431,7 @@ static int bus_send_hello(sd_bus *bus) {
int bus_start_running(sd_bus *bus) {
assert(bus);
- if (bus->bus_client && !bus->is_kernel) {
+ if (bus->bus_client) {
bus->state = BUS_HELLO;
return 1;
}
@@ -472,7 +464,7 @@ static int parse_address_key(const char **p, const char *key, char **value) {
} else
a = *p;
- while (*a != ';' && *a != ',' && *a != 0) {
+ while (!IN_SET(*a, ';', ',', 0)) {
char c;
if (*a == '%') {
@@ -541,7 +533,7 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
assert(*p);
assert(guid);
- while (**p != 0 && **p != ';') {
+ while (!IN_SET(**p, 0, ';')) {
r = parse_address_key(p, "guid", guid);
if (r < 0)
return r;
@@ -606,7 +598,7 @@ static int parse_tcp_address(sd_bus *b, const char **p, char **guid) {
assert(*p);
assert(guid);
- while (**p != 0 && **p != ';') {
+ while (!IN_SET(**p, 0, ';')) {
r = parse_address_key(p, "guid", guid);
if (r < 0)
return r;
@@ -674,7 +666,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
assert(*p);
assert(guid);
- while (**p != 0 && **p != ';') {
+ while (!IN_SET(**p, 0, ';')) {
r = parse_address_key(p, "guid", guid);
if (r < 0)
goto fail;
@@ -755,43 +747,6 @@ fail:
return r;
}
-static int parse_kernel_address(sd_bus *b, const char **p, char **guid) {
- _cleanup_free_ char *path = NULL;
- int r;
-
- assert(b);
- assert(p);
- assert(*p);
- assert(guid);
-
- while (**p != 0 && **p != ';') {
- r = parse_address_key(p, "guid", guid);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_address_key(p, "path", &path);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- skip_address_key(p);
- }
-
- if (!path)
- return -EINVAL;
-
- free(b->kernel);
- b->kernel = path;
- path = NULL;
-
- b->is_local = true;
-
- return 0;
-}
-
static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) {
_cleanup_free_ char *machine = NULL, *pid = NULL;
int r;
@@ -801,7 +756,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
assert(*p);
assert(guid);
- while (**p != 0 && **p != ';') {
+ while (!IN_SET(**p, 0, ';')) {
r = parse_address_key(p, "guid", guid);
if (r < 0)
return r;
@@ -852,67 +807,6 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
return 0;
}
-static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid) {
- _cleanup_free_ char *machine = NULL, *pid = NULL;
- int r;
-
- assert(b);
- assert(p);
- assert(*p);
- assert(guid);
-
- while (**p != 0 && **p != ';') {
- r = parse_address_key(p, "guid", guid);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_address_key(p, "machine", &machine);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_address_key(p, "pid", &pid);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- skip_address_key(p);
- }
-
- if (!machine == !pid)
- return -EINVAL;
-
- if (machine) {
- if (!machine_name_is_valid(machine))
- return -EINVAL;
-
- free(b->machine);
- b->machine = machine;
- machine = NULL;
- } else {
- b->machine = mfree(b->machine);
- }
-
- if (pid) {
- r = parse_pid(pid, &b->nspid);
- if (r < 0)
- return r;
- } else
- b->nspid = 0;
-
- r = free_and_strdup(&b->kernel, "/sys/fs/kdbus/0-system/bus");
- if (r < 0)
- return r;
-
- b->is_local = false;
-
- return 0;
-}
-
static void bus_reset_parsed_address(sd_bus *b) {
assert(b);
@@ -921,7 +815,6 @@ static void bus_reset_parsed_address(sd_bus *b) {
b->exec_argv = strv_free(b->exec_argv);
b->exec_path = mfree(b->exec_path);
b->server_id = SD_ID128_NULL;
- b->kernel = mfree(b->kernel);
b->machine = mfree(b->machine);
b->nspid = 0;
}
@@ -975,14 +868,6 @@ static int bus_parse_next_address(sd_bus *b) {
break;
- } else if (startswith(a, "kernel:")) {
-
- a += 7;
- r = parse_kernel_address(b, &a, &guid);
- if (r < 0)
- return r;
-
- break;
} else if (startswith(a, "x-machine-unix:")) {
a += 15;
@@ -991,14 +876,6 @@ static int bus_parse_next_address(sd_bus *b) {
return r;
break;
- } else if (startswith(a, "x-machine-kernel:")) {
-
- a += 17;
- r = parse_container_kernel_address(b, &a, &guid);
- if (r < 0)
- return r;
-
- break;
}
a = strchr(a, ';');
@@ -1017,68 +894,43 @@ static int bus_parse_next_address(sd_bus *b) {
}
static int bus_start_address(sd_bus *b) {
- bool container_kdbus_available = false;
- bool kdbus_available = false;
int r;
assert(b);
for (;;) {
- bool skipped = false;
-
bus_close_fds(b);
- /*
- * 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 you provide multiple different bus-addresses, we
+ * try all of them in order and use the first one that
+ * succeeds. */
if (b->exec_path)
r = bus_socket_exec(b);
- 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;
-
- } else if (b->kernel) {
- r = bus_kernel_connect(b);
- if (r < 0 && !IN_SET(r, -ENOENT, -ESOCKTNOSUPPORT))
- kdbus_available = true;
-
- } else if (b->sockaddr.sa.sa_family != AF_UNSPEC) {
- if (!kdbus_available)
- r = bus_socket_connect(b);
- else
- skipped = true;
- } else
- skipped = true;
- if (!skipped) {
- if (r >= 0) {
- r = attach_io_events(b);
- if (r >= 0)
- return r;
- }
+ 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;
- b->last_connect_error = -r;
+ if (r >= 0) {
+ r = attach_io_events(b);
+ if (r >= 0)
+ return r;
}
+ b->last_connect_error = -r;
+
+ next:
r = bus_parse_next_address(b);
if (r < 0)
return r;
if (r == 0)
- return b->last_connect_error ? -b->last_connect_error : -ECONNREFUSED;
+ return b->last_connect_error > 0 ? -b->last_connect_error : -ECONNREFUSED;
}
}
@@ -1118,10 +970,7 @@ static int bus_start_fd(sd_bus *b) {
if (fstat(b->input_fd, &st) < 0)
return -errno;
- if (S_ISCHR(b->input_fd))
- return bus_kernel_take_fd(b);
- else
- return bus_socket_take_fd(b);
+ return bus_socket_take_fd(b);
}
_public_ int sd_bus_start(sd_bus *bus) {
@@ -1138,7 +987,7 @@ _public_ int sd_bus_start(sd_bus *bus) {
if (bus->input_fd >= 0)
r = bus_start_fd(bus);
- else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->kernel || bus->machine)
+ else if (bus->address || bus->sockaddr.sa.sa_family != AF_UNSPEC || bus->exec_path || bus->machine)
r = bus_start_address(bus);
else
return -EINVAL;
@@ -1256,8 +1105,7 @@ fail:
int bus_set_address_user(sd_bus *b) {
const char *e;
- uid_t uid;
- int r;
+ _cleanup_free_ char *ee = NULL, *s = NULL;
assert(b);
@@ -1265,25 +1113,20 @@ int bus_set_address_user(sd_bus *b) {
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) {
- _cleanup_free_ char *ee = NULL;
-
- ee = bus_address_escape(e);
- if (!ee)
- return -ENOMEM;
+ if (!e)
+ return -ENOENT;
- (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, ee);
- } else
- (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, uid);
+ ee = bus_address_escape(e);
+ if (!ee)
+ return -ENOMEM;
- if (!b->address)
+ if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, ee) < 0)
return -ENOMEM;
+ b->address = s;
+ s = NULL;
+
return 0;
}
@@ -1299,7 +1142,7 @@ _public_ int sd_bus_open_user(sd_bus **ret) {
r = bus_set_address_user(b);
if (r < 0)
- return r;
+ goto fail;
b->bus_client = true;
b->is_user = true;
@@ -1344,7 +1187,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
if (!e)
return -ENOMEM;
- c = strjoina(",argv4=--machine=", m);
+ c = strjoina(",argv5=--machine=", m);
}
}
@@ -1354,7 +1197,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
return -ENOMEM;
}
- b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=", e, ",argv3=systemd-stdio-bridge", c);
+ b->address = strjoin("unixexec:path=ssh,argv1=-xT,argv2=--,argv3=", e, ",argv4=systemd-stdio-bridge", c);
if (!b->address)
return -ENOMEM;
@@ -1403,7 +1246,7 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) {
if (!e)
return -ENOMEM;
- b->address = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e);
+ b->address = strjoin("x-machine-unix:machine=", e);
if (!b->address)
return -ENOMEM;
@@ -1460,13 +1303,7 @@ _public_ void sd_bus_close(sd_bus *bus) {
* the bus object and the bus may be freed */
bus_reset_queues(bus);
- if (!bus->is_kernel)
- bus_close_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_fds(bus);
}
_public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
@@ -1483,10 +1320,7 @@ _public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) {
static void bus_enter_closing(sd_bus *bus) {
assert(bus);
- if (bus->state != BUS_OPENING &&
- bus->state != BUS_AUTHENTICATING &&
- bus->state != BUS_HELLO &&
- bus->state != BUS_RUNNING)
+ if (!IN_SET(bus->state, BUS_OPENING, BUS_AUTHENTICATING, BUS_HELLO, BUS_RUNNING))
return;
bus->state = BUS_CLOSING;
@@ -1594,14 +1428,6 @@ static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
if (b->message_endian != 0 && b->message_endian != (*m)->header->endian)
remarshal = true;
- /* TODO: kdbus-messages received from the kernel contain data which is
- * not allowed to be passed to KDBUS_CMD_SEND. Therefore, we have to
- * force remarshaling of the message. Technically, we could just
- * recreate the kdbus message, but that is non-trivial as other parts of
- * the message refer to m->kdbus already. This should be fixed! */
- if ((*m)->kdbus && (*m)->release_kdbus)
- remarshal = true;
-
return remarshal ? bus_message_remarshal(b, m) : 0;
}
@@ -1635,16 +1461,12 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
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);
-
+ r = bus_socket_write_message(bus, m, idx);
if (r <= 0)
return r;
- 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=%s",
+ if (*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",
bus_message_type_to_string(m->header->type),
strna(sd_bus_message_get_sender(m)),
strna(sd_bus_message_get_destination(m)),
@@ -1653,6 +1475,7 @@ static int bus_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
strna(sd_bus_message_get_member(m)),
BUS_MESSAGE_COOKIE(m),
m->reply_cookie,
+ strna(m->error.name),
strna(m->error.message));
return r;
@@ -1662,7 +1485,7 @@ static int dispatch_wqueue(sd_bus *bus) {
int r, ret = 0;
assert(bus);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
while (bus->wqueue_size > 0) {
@@ -1672,7 +1495,7 @@ static int dispatch_wqueue(sd_bus *bus) {
else if (r == 0)
/* Didn't do anything this time */
return ret;
- else if (bus->is_kernel || bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
+ else if (bus->windex >= BUS_MESSAGE_SIZE(bus->wqueue[0])) {
/* Fully written. Let's drop the entry from
* the queue.
*
@@ -1698,10 +1521,7 @@ static int dispatch_wqueue(sd_bus *bus) {
static int bus_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
assert(bus);
- if (bus->is_kernel)
- return bus_kernel_read_message(bus, hint_priority, priority);
- else
- return bus_socket_read_message(bus);
+ return bus_socket_read_message(bus);
}
int bus_rqueue_make_room(sd_bus *bus) {
@@ -1721,7 +1541,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
assert(bus);
assert(m);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
/* Note that the priority logic is only available on kdbus,
* where the rqueue is unused. We check the rqueue here
@@ -1758,7 +1578,6 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
bus = m->bus;
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
@@ -1791,7 +1610,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
if (m->dont_send)
goto finish;
- if ((bus->state == BUS_RUNNING || bus->state == BUS_HELLO) && bus->wqueue_size <= 0) {
+ if (IN_SET(bus->state, BUS_RUNNING, BUS_HELLO) && bus->wqueue_size <= 0) {
size_t idx = 0;
r = bus_write_message(bus, m, hint_sync_call, &idx);
@@ -1804,7 +1623,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
return r;
}
- if (!bus->is_kernel && idx < BUS_MESSAGE_SIZE(m)) {
+ if (idx < BUS_MESSAGE_SIZE(m)) {
/* Wasn't fully written. So let's remember how
* much was written. Note that the first entry
* of the wqueue array is always allocated so
@@ -1910,7 +1729,6 @@ _public_ int sd_bus_call_async(
bus = m->bus;
assert_return(!bus_pid_changed(bus), -ECHILD);
- assert_return(!bus->is_kernel || !(bus->hello_flags & KDBUS_HELLO_MONITOR), -EROFS);
if (!BUS_IS_OPEN(bus->state))
return -ENOTCONN;
@@ -1969,7 +1787,7 @@ int bus_ensure_running(sd_bus *bus) {
assert(bus);
- if (bus->state == BUS_UNSET || bus->state == BUS_CLOSED || bus->state == BUS_CLOSING)
+ if (IN_SET(bus->state, BUS_UNSET, BUS_CLOSED, BUS_CLOSING))
return -ENOTCONN;
if (bus->state == BUS_RUNNING)
return 1;
@@ -2011,7 +1829,6 @@ _public_ int sd_bus_call(
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);
if (!BUS_IS_OPEN(bus->state)) {
r = -ENOTCONN;
@@ -2174,7 +1991,7 @@ _public_ int sd_bus_get_events(sd_bus *bus) {
flags |= POLLIN;
- } else if (bus->state == BUS_RUNNING || bus->state == BUS_HELLO) {
+ } else if (IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)) {
if (bus->rqueue_size <= 0)
flags |= POLLIN;
if (bus->wqueue_size > 0)
@@ -2209,7 +2026,7 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) {
return 1;
}
- if (bus->state != BUS_RUNNING && bus->state != BUS_HELLO) {
+ if (!IN_SET(bus->state, BUS_RUNNING, BUS_HELLO)) {
*timeout_usec = (uint64_t) -1;
return 0;
}
@@ -2306,8 +2123,7 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) {
* here (we leave that to the usual handling), we just verify
* we don't let any earlier msg through. */
- if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
- m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
+ if (!IN_SET(m->header->type, SD_BUS_MESSAGE_METHOD_RETURN, SD_BUS_MESSAGE_METHOD_ERROR))
return -EIO;
if (m->reply_cookie != 1)
@@ -2326,11 +2142,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) {
assert(bus);
assert(m);
- if (m->header->type != SD_BUS_MESSAGE_METHOD_RETURN &&
- m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
- return 0;
-
- if (bus->is_kernel && (bus->hello_flags & KDBUS_HELLO_MONITOR))
+ if (!IN_SET(m->header->type, SD_BUS_MESSAGE_METHOD_RETURN, SD_BUS_MESSAGE_METHOD_ERROR))
return 0;
if (m->destination && bus->unique_name && !streq_ptr(m->destination, bus->unique_name))
@@ -2599,7 +2411,7 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd
int r;
assert(bus);
- assert(bus->state == BUS_RUNNING || bus->state == BUS_HELLO);
+ assert(IN_SET(bus->state, BUS_RUNNING, BUS_HELLO));
r = process_timeout(bus);
if (r != 0)
@@ -3046,7 +2858,6 @@ _public_ int sd_bus_add_match(
}
s->match_callback.callback = callback;
- s->match_callback.cookie = ++bus->match_cookie;
if (bus->bus_client) {
enum bus_match_scope scope;
@@ -3054,23 +2865,19 @@ _public_ int sd_bus_add_match(
scope = bus_match_get_scope(components, n_components);
/* Do not install server-side matches for matches
- * against the local service, interface or bus
- * path. */
+ * against the local service, interface or bus path. */
if (scope != BUS_MATCH_LOCAL) {
- 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 */
+ /* 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);
+ r = bus_add_match_internal(bus, s->match_callback.match_string, components, n_components);
if (r < 0)
goto finish;
@@ -3131,7 +2938,7 @@ bool bus_pid_changed(sd_bus *bus) {
/* We don't support people creating a bus connection and
* keeping it around over a fork(). Let's complain. */
- return bus->original_pid != getpid();
+ return bus->original_pid != getpid_cached();
}
static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -3683,29 +3490,10 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
}
_public_ int sd_bus_try_close(sd_bus *bus) {
- int r;
-
assert_return(bus, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- 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;
+ return -EOPNOTSUPP;
}
_public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
@@ -3737,32 +3525,10 @@ int bus_get_root_path(sd_bus *bus) {
}
_public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
- int r;
-
assert_return(bus, -EINVAL);
assert_return(scope, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
- if (bus->is_kernel) {
- _cleanup_free_ char *n = NULL;
- const char *dash;
-
- r = bus_kernel_get_bus_name(bus, &n);
- if (r < 0)
- return r;
-
- if (streq(n, "0-system")) {
- *scope = "system";
- return 0;
- }
-
- dash = strchr(n, '-');
- if (streq_ptr(dash, "-user")) {
- *scope = "user";
- return 0;
- }
- }
-
if (bus->is_user) {
*scope = "user";
return 0;
diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c
index 56ac2ab3dd..6f0ca47df6 100644
--- a/src/libsystemd/sd-bus/test-bus-benchmark.c
+++ b/src/libsystemd/sd-bus/test-bus-benchmark.c
@@ -35,7 +35,6 @@
static usec_t arg_loop_usec = 100 * USEC_PER_MSEC;
typedef enum Type {
- TYPE_KDBUS,
TYPE_LEGACY,
TYPE_DIRECT,
} Type;
@@ -190,9 +189,6 @@ static void client_chart(Type type, const char *address, const char *server_name
assert_se(r >= 0);
switch (type) {
- case TYPE_KDBUS:
- printf("SIZE\tCOPY\tMEMFD\n");
- break;
case TYPE_LEGACY:
printf("SIZE\tLEGACY\n");
break;
@@ -203,25 +199,10 @@ static void client_chart(Type type, const char *address, const char *server_name
for (csize = 1; csize <= MAX_SIZE; csize *= 2) {
usec_t t;
- unsigned n_copying, n_memfd;
+ unsigned n_memfd;
printf("%zu\t", csize);
- if (type == TYPE_KDBUS) {
- b->use_memfd = 0;
-
- t = now(CLOCK_MONOTONIC);
- for (n_copying = 0;; n_copying++) {
- transaction(b, csize, server_name);
- if (now(CLOCK_MONOTONIC) >= t + arg_loop_usec)
- break;
- }
-
- printf("%u\t", (unsigned) ((n_copying * USEC_PER_SEC) / arg_loop_usec));
-
- b->use_memfd = -1;
- }
-
t = now(CLOCK_MONOTONIC);
for (n_memfd = 0;; n_memfd++) {
transaction(b, csize, server_name);
@@ -245,7 +226,7 @@ int main(int argc, char *argv[]) {
MODE_BISECT,
MODE_CHART,
} mode = MODE_BISECT;
- Type type = TYPE_KDBUS;
+ Type type = TYPE_LEGACY;
int i, pair[2] = { -1, -1 };
_cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *server_name = NULL;
_cleanup_close_ int bus_ref = -1;
@@ -271,22 +252,9 @@ int main(int argc, char *argv[]) {
assert_se(parse_sec(argv[i], &arg_loop_usec) >= 0);
}
- assert_se(!MODE_BISECT || TYPE_KDBUS);
-
assert_se(arg_loop_usec > 0);
- if (type == TYPE_KDBUS) {
- assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 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);
- } else if (type == TYPE_LEGACY) {
+ if (type == TYPE_LEGACY) {
const char *e;
e = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c
index 250a5b2908..4d81e67a6b 100644
--- a/src/libsystemd/sd-bus/test-bus-cleanup.c
+++ b/src/libsystemd/sd-bus/test-bus-cleanup.c
@@ -37,8 +37,8 @@ static int test_bus_open(void) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
- r = sd_bus_open_system(&bus);
- if (r == -ECONNREFUSED || r == -ENOENT)
+ r = sd_bus_open_user(&bus);
+ if (IN_SET(r, -ECONNREFUSED, -ENOENT))
return r;
assert_se(r >= 0);
@@ -51,7 +51,7 @@ static void test_bus_new_method_call(void) {
sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- assert_se(sd_bus_open_system(&bus) >= 0);
+ assert_se(sd_bus_open_user(&bus) >= 0);
assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path", "an.interface.name", "AMethodName") >= 0);
@@ -65,7 +65,7 @@ static void test_bus_new_signal(void) {
sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- assert_se(sd_bus_open_system(&bus) >= 0);
+ assert_se(sd_bus_open_user(&bus) >= 0);
assert_se(sd_bus_message_new_signal(bus, &m, "/an/object/path", "an.interface.name", "Name") >= 0);
diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c
index 83f114a0fe..94fa964595 100644
--- a/src/libsystemd/sd-bus/test-bus-gvariant.c
+++ b/src/libsystemd/sd-bus/test-bus-gvariant.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_GLIB
+#if HAVE_GLIB
#include <glib.h>
#endif
@@ -137,7 +137,7 @@ static void test_marshal(void) {
size_t sz;
int r;
- r = sd_bus_open_system(&bus);
+ r = sd_bus_open_user(&bus);
if (r < 0)
exit(EXIT_TEST_SKIP);
@@ -155,7 +155,7 @@ static void test_marshal(void) {
assert_se(bus_message_seal(m, 4711, 0) >= 0);
-#ifdef HAVE_GLIB
+#if HAVE_GLIB
{
GVariant *v;
char *t;
@@ -184,7 +184,7 @@ static void test_marshal(void) {
assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
-#ifdef HAVE_GLIB
+#if HAVE_GLIB
{
GVariant *v;
char *t;
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
deleted file mode 100644
index eb6179d7d2..0000000000
--- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/***
- 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 "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()) >= 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;
-}
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
deleted file mode 100644
index 2214817312..0000000000
--- a/src/libsystemd/sd-bus/test-bus-kernel.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/***
- 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 "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()) >= 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;
-}
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index a28cc5b79e..221dbd35cc 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -20,11 +20,11 @@
#include <math.h>
#include <stdlib.h>
-#ifdef HAVE_GLIB
+#if HAVE_GLIB
#include <gio/gio.h>
#endif
-#ifdef HAVE_DBUS
+#if HAVE_DBUS
#include <dbus/dbus.h>
#endif
@@ -137,7 +137,7 @@ int main(int argc, char *argv[]) {
double dbl;
uint64_t u64;
- r = sd_bus_default_system(&bus);
+ r = sd_bus_default_user(&bus);
if (r < 0)
return EXIT_TEST_SKIP;
@@ -215,7 +215,7 @@ int main(int argc, char *argv[]) {
log_info("message size = %zu, contents =\n%s", sz, h);
free(h);
-#ifdef HAVE_GLIB
+#if HAVE_GLIB
{
GDBusMessage *g;
char *p;
@@ -232,7 +232,7 @@ int main(int argc, char *argv[]) {
}
#endif
-#ifdef HAVE_DBUS
+#if HAVE_DBUS
{
DBusMessage *w;
DBusError error;
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
index 29c4529f95..8fd9d03ddf 100644
--- a/src/libsystemd/sd-bus/test-bus-match.c
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -94,7 +94,7 @@ int main(int argc, char *argv[]) {
sd_bus_slot slots[19];
int r;
- r = sd_bus_open_system(&bus);
+ r = sd_bus_open_user(&bus);
if (r < 0)
return EXIT_TEST_SKIP;
diff --git a/src/libsystemd/sd-bus/test-bus-track.c b/src/libsystemd/sd-bus/test-bus-track.c
index 06c6167511..5f5661cb33 100644
--- a/src/libsystemd/sd-bus/test-bus-track.c
+++ b/src/libsystemd/sd-bus/test-bus-track.c
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
r = sd_event_default(&event);
assert_se(r >= 0);
- r = sd_bus_open_system(&a);
+ r = sd_bus_open_user(&a);
if (IN_SET(r, -ECONNREFUSED, -ENOENT)) {
log_info("Failed to connect to bus, skipping tests.");
return EXIT_TEST_SKIP;
@@ -74,7 +74,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
assert_se(r >= 0);
- r = sd_bus_open_system(&b);
+ r = sd_bus_open_user(&b);
assert_se(r >= 0);
r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL);
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
deleted file mode 100644
index 3380e8500a..0000000000
--- a/src/libsystemd/sd-bus/test-bus-zero-copy.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/***
- 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 "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()) >= 0);
-
- bus_ref = bus_kernel_create_bus(name, false, &bus_name);
- if (bus_ref == -ENOENT)
- return EXIT_TEST_SKIP;
-
- assert_se(bus_ref >= 0);
-
- address = strappend("kernel:path=", bus_name);
- assert_se(address);
-
- r = sd_bus_new(&a);
- assert_se(r >= 0);
-
- r = sd_bus_new(&b);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(a, address);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(b, address);
- assert_se(r >= 0);
-
- r = sd_bus_start(a);
- assert_se(r >= 0);
-
- r = sd_bus_start(b);
- assert_se(r >= 0);
-
- r = sd_bus_get_unique_name(a, &unique);
- assert_se(r >= 0);
-
- r = sd_bus_message_new_method_call(b, &m, unique, "/a/path", "an.inter.face", "AMethod");
- assert_se(r >= 0);
-
- r = sd_bus_message_open_container(m, 'r', "aysay");
- assert_se(r >= 0);
-
- r = sd_bus_message_append_array_space(m, 'y', FIRST_ARRAY, (void**) &p);
- assert_se(r >= 0);
-
- p[0] = '<';
- memset(p+1, 'L', FIRST_ARRAY-2);
- p[FIRST_ARRAY-1] = '>';
-
- f = memfd_new_and_map(NULL, STRING_SIZE, (void**) &s);
- assert_se(f >= 0);
-
- s[0] = '<';
- for (i = 1; i < STRING_SIZE-2; i++)
- s[i] = '0' + (i % 10);
- s[STRING_SIZE-2] = '>';
- s[STRING_SIZE-1] = 0;
- munmap(s, STRING_SIZE);
-
- r = memfd_get_size(f, &sz);
- assert_se(r >= 0);
- assert_se(sz == STRING_SIZE);
-
- r = sd_bus_message_append_string_memfd(m, f, 0, (uint64_t) -1);
- assert_se(r >= 0);
-
- close(f);
-
- f = memfd_new_and_map(NULL, SECOND_ARRAY, (void**) &p);
- assert_se(f >= 0);
-
- p[0] = '<';
- memset(p+1, 'P', SECOND_ARRAY-2);
- p[SECOND_ARRAY-1] = '>';
- munmap(p, SECOND_ARRAY);
-
- r = memfd_get_size(f, &sz);
- assert_se(r >= 0);
- assert_se(sz == SECOND_ARRAY);
-
- r = sd_bus_message_append_array_memfd(m, 'y', f, 0, (uint64_t) -1);
- assert_se(r >= 0);
-
- close(f);
-
- r = sd_bus_message_close_container(m);
- assert_se(r >= 0);
-
- r = sd_bus_message_append(m, "u", 4711);
- assert_se(r >= 0);
-
- assert_se((sfd = memfd_new_and_map(NULL, 6, (void**) &p)) >= 0);
- memcpy(p, "abcd\0", 6);
- munmap(p, 6);
- assert_se(sd_bus_message_append_string_memfd(m, sfd, 1, 4) >= 0);
-
- r = bus_message_seal(m, 55, 99*USEC_PER_SEC);
- assert_se(r >= 0);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
-
- r = sd_bus_send(b, m, NULL);
- assert_se(r >= 0);
-
- sd_bus_message_unref(m);
-
- r = sd_bus_process(a, &m);
- assert_se(r > 0);
-
- bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
- sd_bus_message_rewind(m, true);
-
- r = sd_bus_message_enter_container(m, 'r', "aysay");
- assert_se(r > 0);
-
- r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
- assert_se(r > 0);
- assert_se(l == FIRST_ARRAY);
-
- assert_se(p[0] == '<');
- for (i = 1; i < l-1; i++)
- assert_se(p[i] == 'L');
- assert_se(p[l-1] == '>');
-
- r = sd_bus_message_read(m, "s", &s);
- assert_se(r > 0);
-
- assert_se(s[0] == '<');
- for (i = 1; i < STRING_SIZE-2; i++)
- assert_se(s[i] == (char) ('0' + (i % 10)));
- assert_se(s[STRING_SIZE-2] == '>');
- assert_se(s[STRING_SIZE-1] == 0);
-
- r = sd_bus_message_read_array(m, 'y', (const void**) &p, &l);
- assert_se(r > 0);
- assert_se(l == SECOND_ARRAY);
-
- assert_se(p[0] == '<');
- for (i = 1; i < l-1; i++)
- assert_se(p[i] == 'P');
- assert_se(p[l-1] == '>');
-
- r = sd_bus_message_exit_container(m);
- assert_se(r > 0);
-
- r = sd_bus_message_read(m, "u", &u32);
- assert_se(r > 0);
- assert_se(u32 == 4711);
-
- r = sd_bus_message_read(m, "s", &s);
- assert_se(r > 0);
- assert_se(streq_ptr(s, "bcd"));
-
- sd_bus_message_unref(m);
-
- sd_bus_unref(a);
- sd_bus_unref(b);
-
- return 0;
-}
diff --git a/src/libsystemd/sd-daemon/Makefile b/src/libsystemd/sd-daemon/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/sd-daemon/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 2624ec17a1..cb416fd4b6 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -70,7 +70,7 @@ _public_ int sd_listen_fds(int unset_environment) {
goto finish;
/* Is this for us? */
- if (getpid() != pid) {
+ if (getpid_cached() != pid) {
r = 0;
goto finish;
}
@@ -161,7 +161,7 @@ _public_ int sd_is_fifo(int fd, const char *path) {
if (stat(path, &st_path) < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
+ if (IN_SET(errno, ENOENT, ENOTDIR))
return 0;
return -errno;
@@ -191,7 +191,7 @@ _public_ int sd_is_special(int fd, const char *path) {
if (stat(path, &st_path) < 0) {
- if (errno == ENOENT || errno == ENOTDIR)
+ if (IN_SET(errno, ENOENT, ENOTDIR))
return 0;
return -errno;
@@ -297,8 +297,7 @@ _public_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint
if (l < sizeof(sa_family_t))
return -EINVAL;
- if (sockaddr.sa.sa_family != AF_INET &&
- sockaddr.sa.sa_family != AF_INET6)
+ if (!IN_SET(sockaddr.sa.sa_family, AF_INET, AF_INET6))
return 0;
if (family != 0)
@@ -492,7 +491,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
return 0;
/* Must be an abstract socket, or an absolute path */
- if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+ if (!IN_SET(e[0], '@', '/') || e[1] == 0) {
r = -EINVAL;
goto finish;
}
@@ -519,7 +518,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
send_ucred =
- (pid != 0 && pid != getpid()) ||
+ (pid != 0 && pid != getpid_cached()) ||
getuid() != geteuid() ||
getgid() != getegid();
@@ -662,7 +661,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
goto finish;
/* Is this for us? */
- if (getpid() != pid) {
+ if (getpid_cached() != pid) {
r = 0;
goto finish;
}
diff --git a/src/libsystemd/sd-device/Makefile b/src/libsystemd/sd-device/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/sd-device/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h
index f4783deef8..0505a27304 100644
--- a/src/libsystemd/sd-device/device-internal.h
+++ b/src/libsystemd/sd-device/device-internal.h
@@ -104,6 +104,8 @@ typedef enum DeviceAction {
DEVICE_ACTION_MOVE,
DEVICE_ACTION_ONLINE,
DEVICE_ACTION_OFFLINE,
+ DEVICE_ACTION_BIND,
+ DEVICE_ACTION_UNBIND,
_DEVICE_ACTION_MAX,
_DEVICE_ACTION_INVALID = -1,
} DeviceAction;
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index b4cd676c12..8839c3266c 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -466,6 +466,8 @@ static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
[DEVICE_ACTION_MOVE] = "move",
[DEVICE_ACTION_ONLINE] = "online",
[DEVICE_ACTION_OFFLINE] = "offline",
+ [DEVICE_ACTION_BIND] = "bind",
+ [DEVICE_ACTION_UNBIND] = "unbind",
};
DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index ab36aa2e32..3b5a04d1c3 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -249,7 +249,7 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum)
char id[DECIMAL_STR_MAX(unsigned) * 2 + 1];
assert_return(ret, -EINVAL);
- assert_return(type == 'b' || type == 'c', -EINVAL);
+ assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
/* use /sys/dev/{block,char}/<maj>:<min> link */
snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
@@ -1636,7 +1636,7 @@ static int device_sysattrs_read_all(sd_device *device) {
struct stat statbuf;
/* only handle symlinks and regular files */
- if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
+ if (!IN_SET(dent->d_type, DT_LNK, DT_REG))
continue;
path = strjoina(syspath, "/", dent->d_name);
diff --git a/src/libsystemd/sd-event/Makefile b/src/libsystemd/sd-event/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-event/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index b4686d0065..2c5c2ebb4d 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -436,7 +436,7 @@ _public_ int sd_event_new(sd_event** ret) {
e->watchdog_fd = e->epoll_fd = e->realtime.fd = e->boottime.fd = e->monotonic.fd = e->realtime_alarm.fd = e->boottime_alarm.fd = -1;
e->realtime.next = e->boottime.next = e->monotonic.next = e->realtime_alarm.next = e->boottime_alarm.next = USEC_INFINITY;
e->realtime.wakeup = e->boottime.wakeup = e->monotonic.wakeup = e->realtime_alarm.wakeup = e->boottime_alarm.wakeup = WAKEUP_CLOCK_DATA;
- e->original_pid = getpid();
+ e->original_pid = getpid_cached();
e->perturb = USEC_INFINITY;
r = prioq_ensure_allocated(&e->pending, pending_prioq_compare);
@@ -493,7 +493,7 @@ static bool event_pid_changed(sd_event *e) {
/* We don't support people creating an event loop and keeping
* it around over a fork(). Let's complain. */
- return e->original_pid != getpid();
+ return e->original_pid != getpid_cached();
}
static void source_io_unregister(sd_event_source *s) {
@@ -1597,7 +1597,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
int r;
assert_return(s, -EINVAL);
- assert_return(m == SD_EVENT_OFF || m == SD_EVENT_ON || m == SD_EVENT_ONESHOT, -EINVAL);
+ assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL);
assert_return(!event_pid_changed(s->event), -ECHILD);
/* If we are dead anyway, we are fine with turning off
@@ -2050,7 +2050,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
ss = read(fd, &x, sizeof(x));
if (ss < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
@@ -2139,10 +2139,7 @@ static int process_child(sd_event *e) {
return -errno;
if (s->child.siginfo.si_pid != 0) {
- bool zombie =
- s->child.siginfo.si_code == CLD_EXITED ||
- s->child.siginfo.si_code == CLD_KILLED ||
- s->child.siginfo.si_code == CLD_DUMPED;
+ bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
if (!zombie && (s->child.options & WEXITED)) {
/* If the child isn't dead then let's
@@ -2193,7 +2190,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
n = read(d->fd, &si, sizeof(si));
if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return read_one;
return -errno;
@@ -2235,7 +2232,7 @@ static int source_dispatch(sd_event_source *s) {
* the event. */
saved_type = s->type;
- if (s->type != SOURCE_DEFER && s->type != SOURCE_EXIT) {
+ if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
r = source_set_pending(s, false);
if (r < 0)
return r;
@@ -2287,9 +2284,7 @@ static int source_dispatch(sd_event_source *s) {
case SOURCE_CHILD: {
bool zombie;
- zombie = s->child.siginfo.si_code == CLD_EXITED ||
- s->child.siginfo.si_code == CLD_KILLED ||
- s->child.siginfo.si_code == CLD_DUMPED;
+ zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
r = s->child.callback(s, &s->child.siginfo, s->userdata);
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index 8425378f34..1a581ae23e 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -317,11 +317,11 @@ static void test_rtqueue(void) {
assert_se(sd_event_source_set_priority(v, -10) >= 0);
- assert(sigqueue(getpid(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0);
- assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0);
- assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0);
- assert(sigqueue(getpid(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0);
- assert(sigqueue(getpid(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0);
+ assert(sigqueue(getpid_cached(), SIGRTMIN+2, (union sigval) { .sival_int = 1 }) >= 0);
+ assert(sigqueue(getpid_cached(), SIGRTMIN+3, (union sigval) { .sival_int = 2 }) >= 0);
+ assert(sigqueue(getpid_cached(), SIGUSR2, (union sigval) { .sival_int = 3 }) >= 0);
+ assert(sigqueue(getpid_cached(), SIGRTMIN+3, (union sigval) { .sival_int = 4 }) >= 0);
+ assert(sigqueue(getpid_cached(), SIGUSR2, (union sigval) { .sival_int = 5 }) >= 0);
assert_se(n_rtqueue == 0);
assert_se(last_rtqueue_sigval == 0);
diff --git a/src/libsystemd/sd-hwdb/Makefile b/src/libsystemd/sd-hwdb/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-hwdb/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c
index c155c70162..f8246eaa70 100644
--- a/src/libsystemd/sd-hwdb/sd-hwdb.c
+++ b/src/libsystemd/sd-hwdb/sd-hwdb.c
@@ -317,7 +317,7 @@ static const char hwdb_bin_paths[] =
"/etc/systemd/hwdb/hwdb.bin\0"
"/etc/udev/hwdb.bin\0"
"/usr/lib/systemd/hwdb/hwdb.bin\0"
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib/systemd/hwdb/hwdb.bin\0"
#endif
UDEVLIBEXECDIR "/hwdb.bin\0";
diff --git a/src/libsystemd/sd-id128/Makefile b/src/libsystemd/sd-id128/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-id128/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index e6d45c18e3..f5c017ff8b 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -75,7 +75,7 @@ bool id128_is_valid(const char *s) {
for (i = 0; i < l; i++) {
char c = s[i];
- if ((i == 8 || i == 13 || i == 18 || i == 23)) {
+ if (IN_SET(i, 8, 13, 18, 23)) {
if (c != '-')
return false;
} else {
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index b1f6c5305f..d44d75ece8 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -66,7 +66,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
if (i == 8)
is_guid = true;
- else if (i == 13 || i == 18 || i == 23) {
+ else if (IN_SET(i, 13, 18, 23)) {
if (!is_guid)
return -EINVAL;
} else
diff --git a/src/libsystemd/sd-login/Makefile b/src/libsystemd/sd-login/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/sd-login/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index b618b79b28..02a73f9189 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -55,7 +55,7 @@ static void test_login(void) {
*type = NULL, *class = NULL, *state = NULL, *state2 = NULL,
*seat = NULL, *session = NULL,
*unit = NULL, *user_unit = NULL, *slice = NULL;
- int r, k;
+ int r;
uid_t u, u2;
char *t, **seats, **sessions;
@@ -157,7 +157,7 @@ static void test_login(void) {
if (r >= 0) {
assert_se(seat);
- log_info("sd_session_get_display(\"%s\") → \"%s\"", session, seat);
+ log_info("sd_session_get_seat(\"%s\") → \"%s\"", session, seat);
r = sd_seat_can_multi_session(seat);
assert_se(r >= 0);
@@ -171,7 +171,7 @@ static void test_login(void) {
assert_se(r >= 0);
log_info("sd_session_can_graphical(\"%s\") → %s", seat, yes_no(r));
} else {
- log_info_errno(r, "sd_session_get_display(\"%s\"): %m", session);
+ log_info_errno(r, "sd_session_get_seat(\"%s\"): %m", session);
assert_se(r == -ENODATA);
}
@@ -186,13 +186,14 @@ static void test_login(void) {
assert_se(sd_uid_is_on_seat(u, 0, seat) > 0);
- k = sd_uid_is_on_seat(u, 1, seat);
- assert_se(k >= 0);
- assert_se(!!k == !!r);
-
- assert_se(sd_seat_get_active(seat, &session2, &u2) >= 0);
+ r = sd_seat_get_active(seat, &session2, &u2);
+ assert_se(r >= 0);
log_info("sd_seat_get_active(\"%s\", …) → \"%s\", "UID_FMT, seat, session2, u2);
+ r = sd_uid_is_on_seat(u, 1, seat);
+ assert_se(r >= 0);
+ assert_se(!!r == streq(session, session2));
+
r = sd_seat_get_sessions(seat, &sessions, &uids, &n);
assert_se(r >= 0);
assert_se(r == (int) strv_length(sessions));
diff --git a/src/libsystemd/sd-netlink/Makefile b/src/libsystemd/sd-netlink/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-netlink/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c
index ed9ee041ab..d82ca806a4 100644
--- a/src/libsystemd/sd-netlink/local-addresses.c
+++ b/src/libsystemd/sd-netlink/local-addresses.c
@@ -122,7 +122,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
if (r < 0)
return r;
- if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
+ if (ifindex == 0 && IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
continue;
switch (family) {
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index e8c8abac2a..ac0427f949 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -101,12 +101,8 @@ int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL);
- assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
- m->hdr->nlmsg_type == RTM_GETADDR ||
- m->hdr->nlmsg_type == RTM_GETROUTE ||
- m->hdr->nlmsg_type == RTM_GETNEIGH ||
- m->hdr->nlmsg_type == RTM_GETADDRLABEL ,
- -EINVAL);
+
+ assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 923f7dd10c..979dc6824f 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -22,6 +22,7 @@
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/can/netlink.h>
+#include <linux/fib_rules.h>
#include <linux/in6.h>
#include <linux/veth.h>
#include <linux/if_bridge.h>
@@ -29,8 +30,11 @@
#include <linux/if_addrlabel.h>
#include <linux/if.h>
#include <linux/ip.h>
+#include <linux/if_addr.h>
+#include <linux/if_bridge.h>
#include <linux/if_link.h>
#include <linux/if_tunnel.h>
+#include <linux/fib_rules.h>
#include "macro.h"
#include "missing.h"
@@ -597,6 +601,31 @@ static const NLTypeSystem rtnl_addrlabel_type_system = {
.types = rtnl_addrlabel_types,
};
+static const NLType rtnl_routing_policy_rule_types[] = {
+ [FRA_DST] = { .type = NETLINK_TYPE_IN_ADDR },
+ [FRA_SRC] = { .type = NETLINK_TYPE_IN_ADDR },
+ [FRA_IIFNAME] = { .type = NETLINK_TYPE_STRING },
+ [RTA_OIF] = { .type = NETLINK_TYPE_U32 },
+ [RTA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR },
+ [FRA_PRIORITY] = { .type = NETLINK_TYPE_U32 },
+ [FRA_FWMARK] = { .type = NETLINK_TYPE_U32 },
+ [FRA_FLOW] = { .type = NETLINK_TYPE_U32 },
+ [FRA_TUN_ID] = { .type = NETLINK_TYPE_U32 },
+ [FRA_SUPPRESS_IFGROUP] = { .type = NETLINK_TYPE_U32 },
+ [FRA_SUPPRESS_PREFIXLEN] = { .type = NETLINK_TYPE_U32 },
+ [FRA_TABLE] = { .type = NETLINK_TYPE_U32 },
+ [FRA_FWMASK] = { .type = NETLINK_TYPE_U32 },
+ [FRA_OIFNAME] = { .type = NETLINK_TYPE_STRING },
+ [FRA_PAD] = { .type = NETLINK_TYPE_U32 },
+ [FRA_L3MDEV] = { .type = NETLINK_TYPE_U64 },
+ [FRA_UID_RANGE] = { .size = sizeof(struct fib_rule_uid_range) },
+};
+
+static const NLTypeSystem rtnl_routing_policy_rule_type_system = {
+ .count = ELEMENTSOF(rtnl_routing_policy_rule_types),
+ .types = rtnl_routing_policy_rule_types,
+};
+
static const NLType rtnl_types[] = {
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
@@ -616,6 +645,9 @@ static const NLType rtnl_types[] = {
[RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
[RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) },
+ [RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
+ [RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
+ [RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) },
};
const NLTypeSystem type_system_root = {
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 215af12406..d2fb651204 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -47,6 +47,10 @@ static inline bool rtnl_message_type_is_addrlabel(uint16_t type) {
return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL);
}
+static inline bool rtnl_message_type_is_routing_policy_rule(uint16_t type) {
+ return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE);
+}
+
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 12c51ffe2e..d851ac228f 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -155,6 +155,35 @@ int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) {
return 0;
}
+int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(type, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *type = rtm->rtm_type;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_type = type;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
struct rtmsg *rtm;
@@ -253,7 +282,7 @@ int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
- rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
+ IN_SET(rtm_family, AF_INET, AF_INET6), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -361,9 +390,7 @@ int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16
int r;
assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
- assert_return(ndm_family == AF_INET ||
- ndm_family == AF_INET6 ||
- ndm_family == PF_BRIDGE, -EINVAL);
+ assert_return(IN_SET(ndm_family, AF_INET, AF_INET6, PF_BRIDGE), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -579,7 +606,7 @@ int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
index > 0, -EINVAL);
assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
- family == AF_INET || family == AF_INET6, -EINVAL);
+ IN_SET(family, AF_INET, AF_INET6), -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -697,6 +724,14 @@ int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
*family = ifa->ifa_family;
return 0;
+ } else if (rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type)) {
+ struct rtmsg *rtm;
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *family = rtm->rtm_family;
+
+ return 0;
}
return -EOPNOTSUPP;
@@ -754,3 +789,166 @@ int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char
return 0;
}
+
+int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family) {
+ struct rtmsg *rtm;
+ int r;
+
+ assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = message_new(rtnl, ret, nlmsg_type);
+ if (r < 0)
+ return r;
+
+ if (nlmsg_type == RTM_NEWRULE)
+ (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
+
+ rtm = NLMSG_DATA((*ret)->hdr);
+ rtm->rtm_family = ifal_family;
+ rtm->rtm_protocol = RTPROT_BOOT;
+ rtm->rtm_scope = RT_SCOPE_UNIVERSE;
+ rtm->rtm_type = RTN_UNICAST;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ routing_policy_rule->rtm_tos = tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, unsigned char *tos) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ *tos = routing_policy_rule->rtm_tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ routing_policy_rule->rtm_table = table;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, unsigned char *table) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ *table = routing_policy_rule->rtm_table;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ routing_policy_rule->rtm_type = type;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsigned char *type) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ *type = routing_policy_rule->rtm_type;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ routing_policy_rule->rtm_dst_len = len;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char *len) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ *len = routing_policy_rule->rtm_dst_len;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ routing_policy_rule->rtm_src_len = len;
+
+ return 0;
+}
+
+int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(sd_netlink_message *m, unsigned char *len) {
+ struct rtmsg *routing_policy_rule;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
+
+ routing_policy_rule = NLMSG_DATA(m->hdr);
+
+ *len = routing_policy_rule->rtm_src_len;
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 68435564de..77f4d5b635 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -44,7 +44,7 @@ static int sd_netlink_new(sd_netlink **ret) {
rtnl->n_ref = REFCNT_INIT;
rtnl->fd = -1;
rtnl->sockaddr.nl.nl_family = AF_NETLINK;
- rtnl->original_pid = getpid();
+ rtnl->original_pid = getpid_cached();
LIST_HEAD_INIT(rtnl->match_callbacks);
@@ -99,7 +99,7 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) {
/* We don't support people creating an rtnl connection and
* keeping it around over a fork(). Let's complain. */
- return rtnl->original_pid != getpid();
+ return rtnl->original_pid != getpid_cached();
}
int sd_netlink_open_fd(sd_netlink **ret, int fd) {
@@ -894,6 +894,16 @@ int sd_netlink_add_match(sd_netlink *rtnl,
if (r < 0)
return r;
break;
+ case RTM_NEWRULE:
+ case RTM_DELRULE:
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_RULE);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_RULE);
+ if (r < 0)
+ return r;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 58c2e892f5..83f0395dfe 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -362,7 +362,7 @@ static void test_get_addresses(sd_netlink *rtnl) {
assert_se(sd_rtnl_message_addr_get_flags(m, &flags) >= 0);
assert_se(ifindex > 0);
- assert_se(family == AF_INET || family == AF_INET6);
+ assert_se(IN_SET(family, AF_INET, AF_INET6));
log_info("got IPv%u address on ifindex %i", family == AF_INET ? 4: 6, ifindex);
}
diff --git a/src/libsystemd/sd-network/Makefile b/src/libsystemd/sd-network/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/sd-network/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 8b4af5a2c3..41b97ca1f3 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -342,7 +342,7 @@ _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/libsystemd/sd-path/Makefile b/src/libsystemd/sd-path/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libsystemd/sd-path/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
index 752c1ba56b..6570d01392 100644
--- a/src/libsystemd/sd-path/sd-path.c
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -23,6 +23,7 @@
#include "architecture.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "missing.h"
#include "path-util.h"
#include "string-util.h"
@@ -219,10 +220,10 @@ static int get_path(uint64_t type, char **buffer, const char **ret) {
switch (type) {
case SD_PATH_TEMPORARY:
- return from_environment("TMPDIR", "/tmp", ret);
+ return tmp_dir(ret);
case SD_PATH_TEMPORARY_LARGE:
- return from_environment("TMPDIR", "/var/tmp", ret);
+ return var_tmp_dir(ret);
case SD_PATH_SYSTEM_BINARIES:
*ret = "/usr/bin";
@@ -492,7 +493,7 @@ static int get_search(uint64_t type, char ***list) {
"/usr/local/bin",
"/usr/sbin",
"/usr/bin",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/sbin",
"/bin",
#endif
@@ -506,7 +507,7 @@ static int get_search(uint64_t type, char ***list) {
false,
"/usr/local/lib",
"/usr/lib",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib",
#endif
NULL);
@@ -518,7 +519,7 @@ static int get_search(uint64_t type, char ***list) {
"LD_LIBRARY_PATH",
true,
LIBDIR,
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
ROOTLIBDIR,
#endif
NULL);
diff --git a/src/libsystemd/sd-resolve/Makefile b/src/libsystemd/sd-resolve/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-resolve/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 60aa55de3b..12fae65e6b 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -459,7 +459,7 @@ static bool resolve_pid_changed(sd_resolve *r) {
/* We don't support people creating a resolver and keeping it
* around after fork(). Let's complain. */
- return r->original_pid != getpid();
+ return r->original_pid != getpid_cached();
}
_public_ int sd_resolve_new(sd_resolve **ret) {
@@ -473,7 +473,7 @@ _public_ int sd_resolve_new(sd_resolve **ret) {
return -ENOMEM;
resolve->n_ref = 1;
- resolve->original_pid = getpid();
+ resolve->original_pid = getpid_cached();
for (i = 0; i < _FD_MAX; i++)
resolve->fds[i] = -1;
diff --git a/src/libsystemd/sd-utf8/Makefile b/src/libsystemd/sd-utf8/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/libsystemd/sd-utf8/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/libudev/.gitignore b/src/libudev/.gitignore
deleted file mode 100644
index 0c8a5d5231..0000000000
--- a/src/libudev/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/libudev.pc
diff --git a/src/libudev/Makefile b/src/libudev/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/libudev/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c
index 3b8abfb260..ea80c750c9 100644
--- a/src/libudev/libudev-enumerate.c
+++ b/src/libudev/libudev-enumerate.c
@@ -159,6 +159,8 @@ _public_ struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumer
* Returns: a udev_list_entry.
*/
_public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) {
+ struct udev_list_entry *e;
+
assert_return_errno(udev_enumerate, NULL, EINVAL);
if (!udev_enumerate->devices_uptodate) {
@@ -182,7 +184,11 @@ _public_ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enume
udev_enumerate->devices_uptodate = true;
}
- return udev_list_get_entry(&udev_enumerate->devices_list);
+ e = udev_list_get_entry(&udev_enumerate->devices_list);
+ if (!e)
+ errno = ENODATA;
+
+ return e;
}
/**
diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c
index a53f000015..4bdc37d973 100644
--- a/src/libudev/libudev-hwdb.c
+++ b/src/libudev/libudev-hwdb.c
@@ -57,15 +57,19 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
struct udev_hwdb *hwdb;
int r;
- assert_return(udev, NULL);
+ assert_return_errno(udev, NULL, EINVAL);
r = sd_hwdb_new(&hwdb_internal);
- if (r < 0)
+ if (r < 0) {
+ errno = -r;
return NULL;
+ }
hwdb = new0(struct udev_hwdb, 1);
- if (!hwdb)
+ if (!hwdb) {
+ errno = ENOMEM;
return NULL;
+ }
hwdb->refcount = 1;
hwdb->hwdb = hwdb_internal;
@@ -127,6 +131,7 @@ _public_ struct udev_hwdb *udev_hwdb_unref(struct udev_hwdb *hwdb) {
*/
_public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev_hwdb *hwdb, const char *modalias, unsigned int flags) {
const char *key, *value;
+ struct udev_list_entry *e;
if (!hwdb || !modalias) {
errno = EINVAL;
@@ -142,5 +147,9 @@ _public_ struct udev_list_entry *udev_hwdb_get_properties_list_entry(struct udev
}
}
- return udev_list_get_entry(&hwdb->properties_list);
+ e = udev_list_get_entry(&hwdb->properties_list);
+ if (!e)
+ errno = ENODATA;
+
+ return e;
}
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 8287694c49..32f2154b36 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -100,8 +100,10 @@ static struct udev_monitor *udev_monitor_new(struct udev *udev)
struct udev_monitor *udev_monitor;
udev_monitor = new0(struct udev_monitor, 1);
- if (udev_monitor == NULL)
+ if (udev_monitor == NULL) {
+ errno = ENOMEM;
return NULL;
+ }
udev_monitor->refcount = 1;
udev_monitor->udev = udev;
udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
@@ -171,8 +173,10 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
struct udev_monitor *udev_monitor;
unsigned int group;
- if (udev == NULL)
+ if (udev == NULL) {
+ errno = EINVAL;
return NULL;
+ }
if (name == NULL)
group = UDEV_MONITOR_NONE;
@@ -196,8 +200,10 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
group = UDEV_MONITOR_UDEV;
} else if (streq(name, "kernel"))
group = UDEV_MONITOR_KERNEL;
- else
+ else {
+ errno = EINVAL;
return NULL;
+ }
udev_monitor = udev_monitor_new(udev);
if (udev_monitor == NULL)
@@ -438,7 +444,10 @@ _public_ int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_moni
{
if (udev_monitor == NULL)
return -EINVAL;
- return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
+ if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0)
+ return -errno;
+
+ return 0;
}
int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
@@ -596,8 +605,10 @@ _public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *ud
bool is_initialized = false;
retry:
- if (udev_monitor == NULL)
+ if (udev_monitor == NULL) {
+ errno = EINVAL;
return NULL;
+ }
iov.iov_base = &buf;
iov.iov_len = sizeof(buf);
memzero(&smsg, sizeof(struct msghdr));
@@ -617,6 +628,7 @@ retry:
if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) {
log_debug("invalid message length");
+ errno = EINVAL;
return NULL;
}
@@ -625,12 +637,14 @@ retry:
if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
log_debug("unicast netlink message ignored");
+ errno = EAGAIN;
return NULL;
}
} else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
if (snl.nl.nl_pid > 0) {
log_debug("multicast kernel netlink message from PID %"PRIu32" ignored",
snl.nl.nl_pid);
+ errno = EAGAIN;
return NULL;
}
}
@@ -638,12 +652,14 @@ retry:
cmsg = CMSG_FIRSTHDR(&smsg);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
log_debug("no sender credentials received, message ignored");
+ errno = EAGAIN;
return NULL;
}
cred = (struct ucred *)CMSG_DATA(cmsg);
if (cred->uid != 0) {
log_debug("sender uid="UID_FMT", message ignored", cred->uid);
+ errno = EAGAIN;
return NULL;
}
@@ -652,11 +668,13 @@ retry:
if (buf.nlh.magic != htobe32(UDEV_MONITOR_MAGIC)) {
log_debug("unrecognized message signature (%x != %x)",
buf.nlh.magic, htobe32(UDEV_MONITOR_MAGIC));
+ errno = EAGAIN;
return NULL;
}
if (buf.nlh.properties_off+32 > (size_t)buflen) {
log_debug("message smaller than expected (%u > %zd)",
buf.nlh.properties_off+32, buflen);
+ errno = EAGAIN;
return NULL;
}
@@ -669,12 +687,14 @@ retry:
bufpos = strlen(buf.raw) + 1;
if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
log_debug("invalid message length");
+ errno = EAGAIN;
return NULL;
}
/* check message header */
if (strstr(buf.raw, "@/") == NULL) {
log_debug("unrecognized message header");
+ errno = EAGAIN;
return NULL;
}
}
@@ -701,6 +721,8 @@ retry:
rc = poll(pfd, 1, 0);
if (rc > 0)
goto retry;
+
+ errno = EAGAIN;
return NULL;
}
@@ -837,8 +859,11 @@ _public_ int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor
*/
_public_ int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
{
- static struct sock_fprog filter = { 0, NULL };
+ static const struct sock_fprog filter = { 0, NULL };
udev_list_cleanup(&udev_monitor->filter_subsystem_list);
- return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
+ if (setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) < 0)
+ return -errno;
+
+ return 0;
}
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index e3dffa6925..f3143d4615 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -60,12 +60,16 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
{
struct udev_queue *udev_queue;
- if (udev == NULL)
+ if (udev == NULL) {
+ errno = EINVAL;
return NULL;
+ }
udev_queue = new0(struct udev_queue, 1);
- if (udev_queue == NULL)
+ if (udev_queue == NULL) {
+ errno = ENOMEM;
return NULL;
+ }
udev_queue->refcount = 1;
udev_queue->udev = udev;
@@ -124,8 +128,10 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
**/
_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
{
- if (udev_queue == NULL)
+ if (udev_queue == NULL) {
+ errno = EINVAL;
return NULL;
+ }
return udev_queue->udev;
}
@@ -223,6 +229,7 @@ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, un
**/
_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
{
+ errno = ENODATA;
return NULL;
}
diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c
index 5f2225f402..ce8d5b5760 100644
--- a/src/libudev/libudev.c
+++ b/src/libudev/libudev.c
@@ -94,11 +94,10 @@ _public_ void udev_set_userdata(struct udev *udev, void *userdata) {
**/
_public_ struct udev *udev_new(void) {
struct udev *udev;
- _cleanup_fclose_ FILE *f = NULL;
udev = new0(struct udev, 1);
if (!udev) {
- errno = -ENOMEM;
+ errno = ENOMEM;
return NULL;
}
udev->refcount = 1;
diff --git a/src/libudev/meson.build b/src/libudev/meson.build
index 1378f9a251..57d678fa97 100644
--- a/src/libudev/meson.build
+++ b/src/libudev/meson.build
@@ -19,7 +19,7 @@ libudev_sym_path = '@0@/@1@'.format(meson.current_source_dir(), libudev_sym)
libudev = shared_library(
'udev',
libudev_sources,
- version : '1.6.6',
+ version : libudev_version,
include_directories : includes,
link_args : ['-shared',
'-Wl,--version-script=' + libudev_sym_path],
diff --git a/src/locale/.gitignore b/src/locale/.gitignore
deleted file mode 100644
index b1e0ba755e..0000000000
--- a/src/locale/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-org.freedesktop.locale1.policy
diff --git a/src/locale/Makefile b/src/locale/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/locale/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c
index 105d9b0ee4..b71091f706 100644
--- a/src/locale/keymap-util.c
+++ b/src/locale/keymap-util.c
@@ -39,7 +39,7 @@ static bool startswith_comma(const char *s, const char *prefix) {
if (!s)
return false;
- return *s == ',' || *s == '\0';
+ return IN_SET(*s, ',', '\0');
}
static const char* strnulldash(const char *s) {
@@ -177,7 +177,7 @@ static int x11_read_data(Context *c) {
char_array_0(line);
l = strstrip(line);
- if (l[0] == 0 || l[0] == '#')
+ if (IN_SET(l[0], 0, '#'))
continue;
if (in_section && first_word(l, "Option")) {
@@ -361,12 +361,12 @@ int x11_write_data(Context *c) {
fchmod(fileno(f), 0644);
- fputs("# Written by systemd-localed(8), read by systemd-localed and Xorg. It's\n"
- "# probably wise not to edit this file manually. Use localectl(1) to\n"
- "# instruct systemd-localed to update it.\n"
- "Section \"InputClass\"\n"
- " Identifier \"system-keyboard\"\n"
- " MatchIsKeyboard \"on\"\n", f);
+ fputs_unlocked("# Written by systemd-localed(8), read by systemd-localed and Xorg. It's\n"
+ "# probably wise not to edit this file manually. Use localectl(1) to\n"
+ "# instruct systemd-localed to update it.\n"
+ "Section \"InputClass\"\n"
+ " Identifier \"system-keyboard\"\n"
+ " MatchIsKeyboard \"on\"\n", f);
if (!isempty(c->x11_layout))
fprintf(f, " Option \"XkbLayout\" \"%s\"\n", c->x11_layout);
@@ -380,9 +380,9 @@ int x11_write_data(Context *c) {
if (!isempty(c->x11_options))
fprintf(f, " Option \"XkbOptions\" \"%s\"\n", c->x11_options);
- fputs("EndSection\n", f);
+ fputs_unlocked("EndSection\n", f);
- r = fflush_and_check(f);
+ r = fflush_sync_and_check(f);
if (r < 0)
goto fail;
@@ -394,8 +394,6 @@ int x11_write_data(Context *c) {
return 0;
fail:
- (void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
-
if (temp_path)
(void) unlink(temp_path);
@@ -427,7 +425,7 @@ static int read_next_mapping(const char* filename,
(*n)++;
l = strstrip(line);
- if (l[0] == 0 || l[0] == '#')
+ if (IN_SET(l[0], 0, '#'))
continue;
r = strv_split_extract(&b, l, WHITESPACE, EXTRACT_QUOTES);
diff --git a/src/locale/localed.c b/src/locale/localed.c
index b4798d674c..3c0c167dcf 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -22,7 +22,7 @@
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_XKBCOMMON
+#if HAVE_XKBCOMMON
#include <xkbcommon/xkbcommon.h>
#include <dlfcn.h>
#endif
@@ -429,7 +429,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
return sd_bus_reply_method_return(m, NULL);
}
-#ifdef HAVE_XKBCOMMON
+#if HAVE_XKBCOMMON
_printf_(3, 0)
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
diff --git a/src/locale/meson.build b/src/locale/meson.build
index d7dd113c8d..e9de6089f3 100644
--- a/src/locale/meson.build
+++ b/src/locale/meson.build
@@ -6,7 +6,7 @@ systemd_localed_sources = files('''
localectl_sources = files('localectl.c')
-if conf.get('ENABLE_LOCALED', false)
+if conf.get('ENABLE_LOCALED') == 1
install_data('org.freedesktop.locale1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.locale1.service',
@@ -27,7 +27,7 @@ endif
kbd_model_map = join_paths(meson.current_source_dir(), 'kbd-model-map')
language_fallback_map = join_paths(meson.current_source_dir(), 'language-fallback-map')
-if conf.get('ENABLE_LOCALED', false)
+if conf.get('ENABLE_LOCALED') == 1
install_data('kbd-model-map',
'language-fallback-map',
install_dir : pkgdatadir)
diff --git a/src/login/.gitignore b/src/login/.gitignore
deleted file mode 100644
index 3a8ba497c1..0000000000
--- a/src/login/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/logind-gperf.c
-/logind.conf
-/org.freedesktop.login1.policy
-/71-seat.rules
-/73-seat-late.rules
-/systemd-user
diff --git a/src/login/Makefile b/src/login/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/login/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 1862e8983c..a63174c093 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -407,7 +407,7 @@ static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_mess
if (r < 0)
return r;
- if (contents[0] == 's' || contents[0] == 'o') {
+ if (IN_SET(contents[0], 's', 'o')) {
const char *s;
char **p = (char **) userdata;
diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h
index 1286c6a3cd..606005a6f1 100644
--- a/src/login/logind-acl.h
+++ b/src/login/logind-acl.h
@@ -24,7 +24,7 @@
#include "libudev.h"
-#ifdef HAVE_ACL
+#if HAVE_ACL
int devnode_acl(const char *path,
bool flush,
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index ebe1d68634..ba538559f9 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -29,6 +29,7 @@
#include "cgroup-util.h"
#include "fd-util.h"
#include "logind.h"
+#include "parse-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "udev-util.h"
@@ -286,7 +287,7 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
assert(m);
- if (pid < 1)
+ if (!pid_is_valid(pid))
return -EINVAL;
r = cg_pid_get_unit(pid, &unit);
@@ -310,7 +311,7 @@ int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
assert(m);
assert(user);
- if (pid < 1)
+ if (!pid_is_valid(pid))
return -EINVAL;
r = cg_pid_get_slice(pid, &unit);
@@ -380,6 +381,42 @@ bool manager_shall_kill(Manager *m, const char *user) {
return m->kill_user_processes;
}
+int config_parse_n_autovts(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ unsigned *n = data;
+ unsigned o;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou(rvalue, &o);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse number of autovts, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (o > 15) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *n = o;
+ return 0;
+}
+
static int vt_is_busy(unsigned int vtnr) {
struct vt_stat vt_stat;
int r = 0;
@@ -387,6 +424,9 @@ static int vt_is_busy(unsigned int vtnr) {
assert(vtnr >= 1);
+ /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
+ assert(vtnr <= 15);
+
/* We explicitly open /dev/tty1 here instead of /dev/tty0. If
* we'd open the latter we'd open the foreground tty which
* hence would be unconditionally busy. By opening /dev/tty1
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index c9b7d99818..2342375f20 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -88,7 +88,7 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid,
assert(message);
assert(ret);
- if (uid == UID_INVALID) {
+ if (!uid_is_valid(uid)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
/* Note that we get the owner UID of the session, not the actual client UID here! */
@@ -767,8 +767,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
if (hashmap_size(m->sessions) >= m->sessions_max)
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
- audit_session_from_pid(leader, &audit_id);
- if (audit_id > 0) {
+ (void) audit_session_from_pid(leader, &audit_id);
+ if (audit_session_is_valid(audit_id)) {
/* Keep our session IDs and the audit session IDs in sync */
if (asprintf(&id, "%"PRIu32, audit_id) < 0)
@@ -780,7 +780,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
* ID */
if (hashmap_get(m->sessions, id)) {
log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
- audit_id = 0;
+ audit_id = AUDIT_SESSION_INVALID;
id = mfree(id);
}
@@ -1132,7 +1132,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
- if (uid == UID_INVALID) {
+ if (!uid_is_valid(uid)) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
/* Note that we get the owner UID of the session, not the actual client UID here! */
@@ -1399,7 +1399,6 @@ static int have_multiple_sessions(
static int bus_manager_log_shutdown(
Manager *m,
- InhibitWhat w,
const char *unit_name) {
const char *p, *q;
@@ -1407,18 +1406,15 @@ static int bus_manager_log_shutdown(
assert(m);
assert(unit_name);
- if (w != INHIBIT_SHUTDOWN)
- return 0;
-
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
p = "MESSAGE=System is powering down";
q = "SHUTDOWN=power-off";
- } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
- p = "MESSAGE=System is halting";
- q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
p = "MESSAGE=System is rebooting";
q = "SHUTDOWN=reboot";
+ } else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
+ p = "MESSAGE=System is halting";
+ q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec";
@@ -1484,18 +1480,26 @@ int manager_set_lid_switch_ignore(Manager *m, usec_t until) {
return r;
}
-static void reset_scheduled_shutdown(Manager *m) {
- m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
- m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
- m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
- m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
- m->scheduled_shutdown_timeout = 0;
- m->shutdown_dry_run = false;
+static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
- if (m->unlink_nologin) {
- (void) unlink("/run/nologin");
- m->unlink_nologin = false;
- }
+ static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
+ [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
+ [INHIBIT_SLEEP] = "PrepareForSleep"
+ };
+
+ int active = _active;
+
+ assert(m);
+ assert(w >= 0);
+ assert(w < _INHIBIT_WHAT_MAX);
+ assert(signal_name[w]);
+
+ return sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ signal_name[w],
+ "b",
+ active);
}
static int execute_shutdown_or_sleep(
@@ -1510,35 +1514,33 @@ static int execute_shutdown_or_sleep(
int r;
assert(m);
- assert(w >= 0);
+ assert(w > 0);
assert(w < _INHIBIT_WHAT_MAX);
assert(unit_name);
- bus_manager_log_shutdown(m, w, unit_name);
+ if (w == INHIBIT_SHUTDOWN)
+ bus_manager_log_shutdown(m, unit_name);
- if (m->shutdown_dry_run) {
- log_info("Running in dry run, suppressing action.");
- reset_scheduled_shutdown(m);
- } else {
- r = sd_bus_call_method(
- m->bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartUnit",
- error,
- &reply,
- "ss", unit_name, "replace-irreversibly");
- if (r < 0)
- return r;
+ r = sd_bus_call_method(
+ m->bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartUnit",
+ error,
+ &reply,
+ "ss", unit_name, "replace-irreversibly");
+ if (r < 0)
+ goto error;
- r = sd_bus_message_read(reply, "o", &p);
- if (r < 0)
- return r;
+ r = sd_bus_message_read(reply, "o", &p);
+ if (r < 0)
+ goto error;
- c = strdup(p);
- if (!c)
- return -ENOMEM;
+ c = strdup(p);
+ if (!c) {
+ r = -ENOMEM;
+ goto error;
}
m->action_unit = unit_name;
@@ -1550,6 +1552,12 @@ static int execute_shutdown_or_sleep(
manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
return 0;
+
+error:
+ /* Tell people that they now may take a lock again */
+ send_prepare_for(m, m->action_what, false);
+
+ return r;
}
int manager_dispatch_delayed(Manager *manager, bool timeout) {
@@ -1580,7 +1588,8 @@ int manager_dispatch_delayed(Manager *manager, bool timeout) {
/* Actually do the operation */
r = execute_shutdown_or_sleep(manager, manager->action_what, manager->action_unit, &error);
if (r < 0) {
- log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
+ log_warning("Error during inhibitor-delayed operation (already returned success to client): %s",
+ bus_error_message(&error, r));
manager->action_unit = NULL;
manager->action_what = 0;
@@ -1641,28 +1650,6 @@ static int delay_shutdown_or_sleep(
return 0;
}
-static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
-
- static const char * const signal_name[_INHIBIT_WHAT_MAX] = {
- [INHIBIT_SHUTDOWN] = "PrepareForShutdown",
- [INHIBIT_SLEEP] = "PrepareForSleep"
- };
-
- int active = _active;
-
- assert(m);
- assert(w >= 0);
- assert(w < _INHIBIT_WHAT_MAX);
- assert(signal_name[w]);
-
- return sd_bus_emit_signal(m->bus,
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- signal_name[w],
- "b",
- active);
-}
-
int bus_manager_shutdown_or_sleep_now_or_later(
Manager *m,
const char *unit_name,
@@ -1674,7 +1661,7 @@ int bus_manager_shutdown_or_sleep_now_or_later(
assert(m);
assert(unit_name);
- assert(w >= 0);
+ assert(w > 0);
assert(w <= _INHIBIT_WHAT_MAX);
assert(!m->action_job);
@@ -1835,6 +1822,20 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
error);
}
+static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_do_shutdown_or_sleep(
+ m, message,
+ SPECIAL_HALT_TARGET,
+ INHIBIT_SHUTDOWN,
+ "org.freedesktop.login1.halt",
+ "org.freedesktop.login1.halt-multiple-sessions",
+ "org.freedesktop.login1.halt-ignore-inhibit",
+ NULL,
+ error);
+}
+
static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
@@ -1849,6 +1850,34 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error
error);
}
+static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_do_shutdown_or_sleep(
+ m, message,
+ SPECIAL_HIBERNATE_TARGET,
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "hibernate",
+ error);
+}
+
+static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_do_shutdown_or_sleep(
+ m, message,
+ SPECIAL_HYBRID_SLEEP_TARGET,
+ INHIBIT_SLEEP,
+ "org.freedesktop.login1.hibernate",
+ "org.freedesktop.login1.hibernate-multiple-sessions",
+ "org.freedesktop.login1.hibernate-ignore-inhibit",
+ "hybrid-sleep",
+ error);
+}
+
static int nologin_timeout_handler(
sd_event_source *s,
uint64_t usec,
@@ -1923,6 +1952,25 @@ fail:
return log_error_errno(r, "Failed to write information about scheduled shutdowns: %m");
}
+static void reset_scheduled_shutdown(Manager *m) {
+ assert(m);
+
+ m->scheduled_shutdown_timeout_source = sd_event_source_unref(m->scheduled_shutdown_timeout_source);
+ m->wall_message_timeout_source = sd_event_source_unref(m->wall_message_timeout_source);
+ m->nologin_timeout_source = sd_event_source_unref(m->nologin_timeout_source);
+
+ m->scheduled_shutdown_type = mfree(m->scheduled_shutdown_type);
+ m->scheduled_shutdown_timeout = 0;
+ m->shutdown_dry_run = false;
+
+ if (m->unlink_nologin) {
+ (void) unlink("/run/nologin");
+ m->unlink_nologin = false;
+ }
+
+ (void) unlink("/run/systemd/shutdown/scheduled");
+}
+
static int manager_scheduled_shutdown_handler(
sd_event_source *s,
uint64_t usec,
@@ -1938,18 +1986,46 @@ static int manager_scheduled_shutdown_handler(
if (isempty(m->scheduled_shutdown_type))
return 0;
- if (streq(m->scheduled_shutdown_type, "halt"))
- target = SPECIAL_HALT_TARGET;
- else if (streq(m->scheduled_shutdown_type, "poweroff"))
+ if (streq(m->scheduled_shutdown_type, "poweroff"))
target = SPECIAL_POWEROFF_TARGET;
- else
+ else if (streq(m->scheduled_shutdown_type, "reboot"))
target = SPECIAL_REBOOT_TARGET;
+ else if (streq(m->scheduled_shutdown_type, "halt"))
+ target = SPECIAL_HALT_TARGET;
+ else
+ assert_not_reached("unexpected shutdown type");
- r = execute_shutdown_or_sleep(m, 0, target, &error);
- if (r < 0)
- return log_error_errno(r, "Unable to execute transition to %s: %m", target);
+ /* Don't allow multiple jobs being executed at the same time */
+ if (m->action_what) {
+ r = -EALREADY;
+ log_error("Scheduled shutdown to %s failed: shutdown or sleep operation already in progress", target);
+ goto error;
+ }
+
+ if (m->shutdown_dry_run) {
+ /* We do not process delay inhibitors here. Otherwise, we
+ * would have to be considered "in progress" (like the check
+ * above) for some seconds after our admin has seen the final
+ * wall message. */
+
+ bus_manager_log_shutdown(m, target);
+ log_info("Running in dry run, suppressing action.");
+ reset_scheduled_shutdown(m);
+
+ return 0;
+ }
+
+ r = bus_manager_shutdown_or_sleep_now_or_later(m, target, INHIBIT_SHUTDOWN, &error);
+ if (r < 0) {
+ log_error_errno(r, "Scheduled shutdown to %s failed: %m", target);
+ goto error;
+ }
return 0;
+
+error:
+ reset_scheduled_shutdown(m);
+ return r;
}
static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1961,6 +2037,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
uint64_t elapse;
char *type;
int r;
+ bool dry_run = false;
assert(m);
assert(message);
@@ -1971,10 +2048,14 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
if (startswith(type, "dry-")) {
type += 4;
- m->shutdown_dry_run = true;
+ dry_run = true;
}
- if (streq(type, "reboot")) {
+ if (streq(type, "poweroff")) {
+ action = "org.freedesktop.login1.power-off";
+ action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
+ action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
+ } else if (streq(type, "reboot")) {
action = "org.freedesktop.login1.reboot";
action_multiple_sessions = "org.freedesktop.login1.reboot-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.reboot-ignore-inhibit";
@@ -1982,10 +2063,6 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
action = "org.freedesktop.login1.halt";
action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions";
action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit";
- } else if (streq(type, "poweroff")) {
- action = "org.freedesktop.login1.power-off";
- action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions";
- action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit";
} else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type");
@@ -2015,6 +2092,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
return log_oom();
}
+ m->shutdown_dry_run = dry_run;
+
if (m->nologin_timeout_source) {
r = sd_event_source_set_time(m->nologin_timeout_source, elapse);
if (r < 0)
@@ -2050,12 +2129,9 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_
if (r < 0)
return r;
- if (!isempty(type)) {
- r = update_schedule_file(m);
- if (r < 0)
- return r;
- } else
- (void) unlink("/run/systemd/shutdown/scheduled");
+ r = update_schedule_file(m);
+ if (r < 0)
+ return r;
return sd_bus_reply_method_return(message, NULL);
}
@@ -2089,34 +2165,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, "b", cancelled);
}
-static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
-
- return method_do_shutdown_or_sleep(
- m, message,
- SPECIAL_HIBERNATE_TARGET,
- INHIBIT_SLEEP,
- "org.freedesktop.login1.hibernate",
- "org.freedesktop.login1.hibernate-multiple-sessions",
- "org.freedesktop.login1.hibernate-ignore-inhibit",
- "hibernate",
- error);
-}
-
-static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
-
- return method_do_shutdown_or_sleep(
- m, message,
- SPECIAL_HYBRID_SLEEP_TARGET,
- INHIBIT_SLEEP,
- "org.freedesktop.login1.hibernate",
- "org.freedesktop.login1.hibernate-multiple-sessions",
- "org.freedesktop.login1.hibernate-ignore-inhibit",
- "hybrid-sleep",
- error);
-}
-
static int method_can_shutdown_or_sleep(
Manager *m,
sd_bus_message *message,
@@ -2235,6 +2283,19 @@ static int method_can_reboot(sd_bus_message *message, void *userdata, sd_bus_err
error);
}
+static int method_can_halt(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ return method_can_shutdown_or_sleep(
+ m, message,
+ INHIBIT_SHUTDOWN,
+ "org.freedesktop.login1.halt",
+ "org.freedesktop.login1.halt-multiple-sessions",
+ "org.freedesktop.login1.halt-ignore-inhibit",
+ NULL,
+ error);
+}
+
static int method_can_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
@@ -2587,11 +2648,13 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("FlushDevices", "b", NULL, method_flush_devices, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("Halt", "b", NULL, method_halt, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 0b6a5f3cf4..aca464427b 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -14,7 +14,7 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Login.NAutoVTs, config_parse_unsigned, 0, offsetof(Manager, n_autovts)
+Login.NAutoVTs, config_parse_n_autovts, 0, offsetof(Manager, n_autovts)
Login.ReserveVT, config_parse_unsigned, 0, offsetof(Manager, reserve_vt)
Login.KillUserProcesses, config_parse_bool, 0, offsetof(Manager, kill_user_processes)
Login.KillOnlyUsers, config_parse_strv, 0, offsetof(Manager, kill_only_users)
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 30dac7997b..64a622307e 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -127,7 +127,7 @@ int seat_save(Seat *s) {
if (s->sessions) {
Session *i;
- fputs("SESSIONS=", f);
+ fputs_unlocked("SESSIONS=", f);
LIST_FOREACH(sessions_by_seat, i, s->sessions) {
fprintf(f,
"%s%c",
@@ -135,7 +135,7 @@ int seat_save(Seat *s) {
i->sessions_by_seat_next ? ' ' : '\n');
}
- fputs("UIDS=", f);
+ fputs_unlocked("UIDS=", f);
LIST_FOREACH(sessions_by_seat, i, s->sessions)
fprintf(f,
UID_FMT"%c",
@@ -663,8 +663,7 @@ static bool seat_name_valid_char(char c) {
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
- c == '-' ||
- c == '_';
+ IN_SET(c, '-', '_');
}
bool seat_name_is_valid(const char *name) {
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 22e5349a67..649f3c155e 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -457,7 +457,7 @@ static int method_take_device(sd_bus_message *message, void *userdata, sd_bus_er
goto error;
session_save(s);
- return 0;
+ return 1;
error:
session_device_free(sd);
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 42dfecaffb..736f7d9fc1 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -45,6 +45,7 @@
#include "terminal-util.h"
#include "user-util.h"
#include "util.h"
+#include "process-util.h"
#define RELEASE_USEC (20*USEC_PER_SEC)
@@ -82,6 +83,7 @@ Session* session_new(Manager *m, const char *id) {
s->manager = m;
s->fifo_fd = -1;
s->vtfd = -1;
+ s->audit_id = AUDIT_SESSION_INVALID;
return s;
}
@@ -280,10 +282,10 @@ int session_save(Session *s) {
if (!s->vtnr)
fprintf(f, "POSITION=%u\n", s->position);
- if (s->leader > 0)
+ if (pid_is_valid(s->leader))
fprintf(f, "LEADER="PID_FMT"\n", s->leader);
- if (s->audit_id > 0)
+ if (audit_session_is_valid(s->audit_id))
fprintf(f, "AUDIT=%"PRIu32"\n", s->audit_id);
if (dual_timestamp_is_set(&s->timestamp))
@@ -459,9 +461,8 @@ int session_load(Session *s) {
}
if (leader) {
- k = parse_pid(leader, &s->leader);
- if (k >= 0)
- audit_session_from_pid(s->leader, &s->audit_id);
+ if (parse_pid(leader, &s->leader) >= 0)
+ (void) audit_session_from_pid(s->leader, &s->audit_id);
}
if (type) {
@@ -1136,7 +1137,7 @@ void session_restore_vt(Session *s) {
};
_cleanup_free_ char *utf8 = NULL;
- int vt, kb, old_fd;
+ int vt, old_fd;
/* We need to get a fresh handle to the virtual terminal,
* since the old file-descriptor is potentially in a hung-up
@@ -1155,12 +1156,7 @@ void session_restore_vt(Session *s) {
(void) ioctl(vt, KDSETMODE, KD_TEXT);
- if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
- kb = K_UNICODE;
- else
- kb = K_XLATE;
-
- (void) ioctl(vt, KDSKBMODE, kb);
+ (void) vt_reset_keyboard(vt);
(void) ioctl(vt, VT_SETMODE, &mode);
(void) fchown(vt, 0, (gid_t) -1);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 1f4a67b21b..ddadd61142 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -183,18 +183,18 @@ static int user_save_internal(User *u) {
Session *i;
bool first;
- fputs("SESSIONS=", f);
+ fputs_unlocked("SESSIONS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->id, f);
+ fputs_unlocked(i->id, f);
}
- fputs("\nSEATS=", f);
+ fputs_unlocked("\nSEATS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (!i->seat)
@@ -203,12 +203,12 @@ static int user_save_internal(User *u) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->seat->id, f);
+ fputs_unlocked(i->seat->id, f);
}
- fputs("\nACTIVE_SESSIONS=", f);
+ fputs_unlocked("\nACTIVE_SESSIONS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (!session_is_active(i))
@@ -217,12 +217,12 @@ static int user_save_internal(User *u) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->id, f);
+ fputs_unlocked(i->id, f);
}
- fputs("\nONLINE_SESSIONS=", f);
+ fputs_unlocked("\nONLINE_SESSIONS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (session_get_state(i) == SESSION_CLOSING)
@@ -231,12 +231,12 @@ static int user_save_internal(User *u) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->id, f);
+ fputs_unlocked(i->id, f);
}
- fputs("\nACTIVE_SEATS=", f);
+ fputs_unlocked("\nACTIVE_SEATS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (!session_is_active(i) || !i->seat)
@@ -245,12 +245,12 @@ static int user_save_internal(User *u) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->seat->id, f);
+ fputs_unlocked(i->seat->id, f);
}
- fputs("\nONLINE_SEATS=", f);
+ fputs_unlocked("\nONLINE_SEATS=", f);
first = true;
LIST_FOREACH(sessions_by_user, i, u->sessions) {
if (session_get_state(i) == SESSION_CLOSING || !i->seat)
@@ -259,11 +259,11 @@ static int user_save_internal(User *u) {
if (first)
first = false;
else
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(i->seat->id, f);
+ fputs_unlocked(i->seat->id, f);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
r = fflush_and_check(f);
@@ -387,7 +387,7 @@ static int user_mkdir_runtime_path(User *u) {
r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID|MS_NOEXEC, t);
if (r < 0) {
- if (errno != EPERM && errno != EACCES) {
+ if (!IN_SET(errno, EPERM, EACCES)) {
r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path);
goto fail;
}
@@ -584,7 +584,7 @@ static int user_remove_runtime_path(User *u) {
* quite possible, if we lacked the permissions to mount
* something */
r = umount2(u->runtime_path, MNT_DETACH);
- if (r < 0 && errno != EINVAL && errno != ENOENT)
+ if (r < 0 && !IN_SET(errno, EINVAL, ENOENT))
log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
r = rm_rf(u->runtime_path, REMOVE_ROOT);
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 311751c2db..00c4cbcf4f 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -31,6 +31,7 @@
#include "bus-util.h"
#include "format-util.h"
#include "logind.h"
+#include "path-util.h"
#include "special.h"
#include "strv.h"
#include "unit-name.h"
@@ -60,15 +61,19 @@ _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
}
bool logind_wall_tty_filter(const char *tty, void *userdata) {
-
Manager *m = userdata;
+ const char *p;
assert(m);
- if (!startswith(tty, "/dev/") || !m->scheduled_shutdown_tty)
+ if (!m->scheduled_shutdown_tty)
+ return true;
+
+ p = path_startswith(tty, "/dev/");
+ if (!p)
return true;
- return !streq(tty + 5, m->scheduled_shutdown_tty);
+ return !streq(p, m->scheduled_shutdown_tty);
}
static int warn_wall(Manager *m, usec_t n) {
diff --git a/src/login/logind.c b/src/login/logind.c
index fb70972b80..6046596684 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -1254,7 +1254,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- log_debug("systemd-logind running as pid "PID_FMT, getpid());
+ log_debug("systemd-logind running as pid "PID_FMT, getpid_cached());
sd_notify(false,
"READY=1\n"
@@ -1262,7 +1262,7 @@ int main(int argc, char *argv[]) {
r = manager_run(m);
- log_debug("systemd-logind stopped as pid "PID_FMT, getpid());
+ log_debug("systemd-logind stopped as pid "PID_FMT, getpid_cached());
finish:
sd_notify(false,
diff --git a/src/login/logind.h b/src/login/logind.h
index 7556ee2e48..2a8c663a7d 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -186,6 +186,7 @@ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, GPERF_LEN_TYPE
int manager_set_lid_switch_ignore(Manager *m, usec_t until);
+int config_parse_n_autovts(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_tmpfs_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_user_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/login/meson.build b/src/login/meson.build
index 26bdbec424..d0723f134f 100644
--- a/src/login/meson.build
+++ b/src/login/meson.build
@@ -39,7 +39,7 @@ liblogind_core_sources = files('''
'''.split())
logind_acl_c = files('logind-acl.c')
-if conf.get('HAVE_ACL', false)
+if conf.get('HAVE_ACL') == 1
liblogind_core_sources += logind_acl_c
endif
@@ -55,7 +55,7 @@ loginctl_sources = files('''
sysfs-show.c
'''.split())
-if conf.get('ENABLE_LOGIND', false)
+if conf.get('ENABLE_LOGIND') == 1
logind_conf = configure_file(
input : 'logind.conf.in',
output : 'logind.conf',
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index d5eb0ff256..de5ae5afe1 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -134,6 +134,10 @@
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
+ send_member="Halt"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Manager"
send_member="Suspend"/>
<allow send_destination="org.freedesktop.login1"
@@ -154,6 +158,10 @@
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
+ send_member="CanHalt"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Manager"
send_member="CanSuspend"/>
<allow send_destination="org.freedesktop.login1"
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
index 66cbce393c..3e8a9bbe3f 100644
--- a/src/login/org.freedesktop.login1.policy.in
+++ b/src/login/org.freedesktop.login1.policy.in
@@ -218,6 +218,39 @@
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
</action>
+ <action id="org.freedesktop.login1.halt">
+ <_description>Halt the system</_description>
+ <_message>Authentication is required for halting the system.</_message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
+ </action>
+
+ <action id="org.freedesktop.login1.halt-multiple-sessions">
+ <_description>Halt the system while other users are logged in</_description>
+ <_message>Authentication is required for halting the system while other users are logged in.</_message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.halt</annotate>
+ </action>
+
+ <action id="org.freedesktop.login1.halt-ignore-inhibit">
+ <_description>Halt the system while an application asked to inhibit it</_description>
+ <_message>Authentication is required for halting the system while an application asked to inhibit it.</_message>
+ <defaults>
+ <allow_any>auth_admin_keep</allow_any>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.halt</annotate>
+ </action>
+
<action id="org.freedesktop.login1.suspend">
<_description>Suspend the system</_description>
<_message>Authentication is required for suspending the system.</_message>
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index df5ce5f547..8b41e03491 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -41,10 +41,12 @@
#include "login-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
+#include "path-util.h"
static int parse_argv(
pam_handle_t *handle,
@@ -339,7 +341,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
type ="tty";
class = "user";
tty = NULL;
- }
+ } else
+ /* Chop off leading /dev prefix that some clients specify, but others do not. */
+ tty = skip_dev_prefix(tty);
/* If this fails vtnr will be 0, that's intended */
if (!isempty(cvtnr))
@@ -377,7 +381,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if (debug)
pam_syslog(handle, LOG_DEBUG, "Asking logind to create session: "
"uid="UID_FMT" pid="PID_FMT" service=%s type=%s class=%s desktop=%s seat=%s vtnr=%"PRIu32" tty=%s display=%s remote=%s remote_user=%s remote_host=%s",
- pw->pw_uid, getpid(),
+ pw->pw_uid, getpid_cached(),
strempty(service),
type, class, strempty(desktop),
strempty(seat), vtnr, strempty(tty), strempty(display),
@@ -392,7 +396,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
&reply,
"uusssssussbssa(sv)",
(uint32_t) pw->pw_uid,
- (uint32_t) getpid(),
+ (uint32_t) getpid_cached(),
service,
type,
class,
diff --git a/src/machine-id-setup/Makefile b/src/machine-id-setup/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/machine-id-setup/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/machine/.gitignore b/src/machine/.gitignore
deleted file mode 100644
index e1065b5894..0000000000
--- a/src/machine/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/org.freedesktop.machine1.policy
diff --git a/src/machine/Makefile b/src/machine/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/machine/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/machine/machine.c b/src/machine/machine.c
index d3433d9b96..399e41f870 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -199,16 +199,16 @@ int machine_save(Machine *m) {
if (m->n_netif > 0) {
unsigned i;
- fputs("NETIF=", f);
+ fputs_unlocked("NETIF=", f);
for (i = 0; i < m->n_netif; i++) {
if (i != 0)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
fprintf(f, "%i", m->netif[i]);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
r = fflush_and_check(f);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index a385e6819b..2447e734a2 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -1458,8 +1458,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- if (arg_transport != BUS_TRANSPORT_LOCAL &&
- arg_transport != BUS_TRANSPORT_MACHINE) {
+ if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
log_error("Login only supported on local machines.");
return -EOPNOTSUPP;
}
@@ -1521,8 +1520,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
assert(bus);
- if (arg_transport != BUS_TRANSPORT_LOCAL &&
- arg_transport != BUS_TRANSPORT_MACHINE) {
+ if (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
log_error("Shell only supported on local machines.");
return -EOPNOTSUPP;
}
diff --git a/src/machine/machined.c b/src/machine/machined.c
index 8719e01de9..d8ddbec8b9 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -34,6 +34,7 @@
#include "label.h"
#include "machine-image.h"
#include "machined.h"
+#include "process-util.h"
#include "signal-util.h"
Manager *manager_new(void) {
@@ -398,7 +399,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- log_debug("systemd-machined running as pid "PID_FMT, getpid());
+ log_debug("systemd-machined running as pid "PID_FMT, getpid_cached());
sd_notify(false,
"READY=1\n"
@@ -406,7 +407,7 @@ int main(int argc, char *argv[]) {
r = manager_run(m);
- log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
+ log_debug("systemd-machined stopped as pid "PID_FMT, getpid_cached());
finish:
manager_free(m);
diff --git a/src/machine/meson.build b/src/machine/meson.build
index 1a0813323c..693503da53 100644
--- a/src/machine/meson.build
+++ b/src/machine/meson.build
@@ -21,7 +21,7 @@ libmachine_core = static_library(
include_directories : includes,
dependencies : [threads])
-if conf.get('ENABLE_MACHINED', false)
+if conf.get('ENABLE_MACHINED') == 1
install_data('org.freedesktop.machine1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.machine1.service',
diff --git a/src/modules-load/Makefile b/src/modules-load/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/modules-load/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 615998a6f6..6efebcd94f 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -264,7 +264,7 @@ int main(int argc, char *argv[]) {
r = k;
}
- k = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ k = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (k < 0) {
log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
if (r == 0)
diff --git a/src/mount/Makefile b/src/mount/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/mount/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c
index ed6578d540..64438cd6d7 100644
--- a/src/mount/mount-tool.c
+++ b/src/mount/mount-tool.c
@@ -30,6 +30,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fstab-util.h"
+#include "mount-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
@@ -330,7 +331,12 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_transport == BUS_TRANSPORT_LOCAL) {
+ if (arg_mount_type && (fstype_is_api_vfs(arg_mount_type) || fstype_is_network(arg_mount_type))) {
+ arg_mount_what = strdup(argv[optind]);
+ if (!arg_mount_what)
+ return log_oom();
+
+ } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
_cleanup_free_ char *u = NULL, *p = NULL;
u = fstab_node_to_udev_node(argv[optind]);
@@ -344,9 +350,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_mount_what = canonicalize_file_name(p);
if (!arg_mount_what)
return log_error_errno(errno, "Failed to canonicalize path: %m");
-
} else {
- arg_mount_what = strdup(argv[optind+1]);
+ arg_mount_what = strdup(argv[optind]);
if (!arg_mount_what)
return log_oom();
@@ -993,14 +998,19 @@ static int action_umount(
r = path_make_absolute_cwd(u, &a);
if (r < 0) {
- r2 = log_error_errno(r, "Failed to make path absolute: %m");
+ r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]);
continue;
}
p = canonicalize_file_name(a);
+ if (!p) {
+ r2 = log_error_errno(errno, "Failed to canonicalize path %s: %m", argv[i]);
+ continue;
+ }
+
if (stat(p, &st) < 0)
- return log_error_errno(errno, "Can't stat %s: %m", p);
+ return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]);
if (S_ISBLK(st.st_mode))
r = umount_by_device(bus, p);
@@ -1009,7 +1019,7 @@ static int action_umount(
else if (S_ISDIR(st.st_mode))
r = stop_mounts(bus, p);
else {
- log_error("Invalid file type: %s", p);
+ log_error("Invalid file type: %s (from %s)", p, argv[i]);
r = -EINVAL;
}
diff --git a/src/network/.gitignore b/src/network/.gitignore
deleted file mode 100644
index 230671763d..0000000000
--- a/src/network/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/networkd-network-gperf.c
-/networkd-gperf.c
diff --git a/src/network/Makefile b/src/network/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/network/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/network/meson.build b/src/network/meson.build
index 35ecd86379..38c2220e8b 100644
--- a/src/network/meson.build
+++ b/src/network/meson.build
@@ -61,6 +61,8 @@ sources = files('''
networkd-network.h
networkd-route.c
networkd-route.h
+ networkd-routing-policy-rule.c
+ networkd-routing-policy-rule.h
networkd-util.c
networkd-util.h
'''.split())
@@ -79,7 +81,7 @@ networkctl_sources = files('networkctl.c')
network_include_dir = include_directories('.')
-if conf.get('ENABLE_NETWORKD', false)
+if conf.get('ENABLE_NETWORKD') == 1
networkd_gperf_c = custom_target(
'networkd-gperf.c',
input : 'networkd-gperf.gperf',
diff --git a/src/network/netdev/.gitignore b/src/network/netdev/.gitignore
deleted file mode 100644
index 0f1a65d2e6..0000000000
--- a/src/network/netdev/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/netdev-gperf.c
diff --git a/src/network/netdev/Makefile b/src/network/netdev/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/network/netdev/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c
index cf6c591f8b..16fff78bf8 100644
--- a/src/network/netdev/bridge.c
+++ b/src/network/netdev/bridge.c
@@ -103,6 +103,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_PRIORITY attribute: %m");
}
+ if (b->group_fwd_mask > 0) {
+ r = sd_netlink_message_append_u16(req, IFLA_BR_GROUP_FWD_MASK, b->group_fwd_mask);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_GROUP_FWD_MASK attribute: %m");
+ }
+
if (b->default_pvid != VLANID_INVALID) {
r = sd_netlink_message_append_u16(req, IFLA_BR_VLAN_DEFAULT_PVID, b->default_pvid);
if (r < 0)
diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h
index 093c60d5b5..b303cfd3f3 100644
--- a/src/network/netdev/bridge.h
+++ b/src/network/netdev/bridge.h
@@ -29,6 +29,7 @@ typedef struct Bridge {
int vlan_filtering;
int stp;
uint16_t priority;
+ uint16_t group_fwd_mask;
uint16_t default_pvid;
usec_t forward_delay;
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 8b235a4857..002efd7e9c 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -56,6 +56,7 @@ Tunnel.Mode, config_parse_ip6tnl_mode, 0,
Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel)
Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp)
Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit)
+Tunnel.Independent, config_parse_bool, 0, offsetof(Tunnel, independent)
Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
@@ -128,9 +129,11 @@ Bridge.MaxAgeSec, config_parse_sec, 0,
Bridge.AgeingTimeSec, config_parse_sec, 0, offsetof(Bridge, ageing_time)
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
Bridge.Priority, config_parse_uint16, 0, offsetof(Bridge, priority)
+Bridge.GroupForwardMask, config_parse_uint16, 0, offsetof(Bridge, group_fwd_mask)
Bridge.DefaultPVID, config_parse_default_port_vlanid, 0, offsetof(Bridge, default_pvid)
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering)
Bridge.STP, config_parse_tristate, 0, offsetof(Bridge, stp)
-VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id)
+VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table) /* deprecated */
+VRF.Table, config_parse_route_table, 0, offsetof(Vrf, table)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 43884581ca..0e1a7d1335 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -601,6 +601,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
_cleanup_free_ NetDev *netdev_raw = NULL;
_cleanup_fclose_ FILE *file = NULL;
const char *dropin_dirname;
+ bool independent = false;
int r;
assert(manager);
@@ -704,13 +705,51 @@ static int netdev_load_one(Manager *manager, const char *filename) {
case NETDEV_CREATE_INDEPENDENT:
r = netdev_create(netdev, NULL, NULL);
if (r < 0)
- return 0;
+ return r;
+
+ break;
+ default:
+ break;
+ }
+ switch (netdev->kind) {
+ case NETDEV_KIND_IPIP:
+ independent = IPIP(netdev)->independent;
+ break;
+ case NETDEV_KIND_GRE:
+ independent = GRE(netdev)->independent;
+ break;
+ case NETDEV_KIND_GRETAP:
+ independent = GRETAP(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6GRE:
+ independent = IP6GRE(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6GRETAP:
+ independent = IP6GRETAP(netdev)->independent;
+ break;
+ case NETDEV_KIND_SIT:
+ independent = SIT(netdev)->independent;
+ break;
+ case NETDEV_KIND_VTI:
+ independent = VTI(netdev)->independent;
+ break;
+ case NETDEV_KIND_VTI6:
+ independent = VTI6(netdev)->independent;
+ break;
+ case NETDEV_KIND_IP6TNL:
+ independent = IP6TNL(netdev)->independent;
break;
default:
break;
}
+ if (independent) {
+ r = netdev_create(netdev, NULL, NULL);
+ if (r < 0)
+ return r;
+ }
+
netdev = NULL;
return 0;
@@ -727,7 +766,7 @@ int netdev_load(Manager *manager) {
while ((netdev = hashmap_first(manager->netdevs)))
netdev_unref(netdev);
- r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
+ r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate netdev files: %m");
diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c
index 67f4fab400..64d87e5e07 100644
--- a/src/network/netdev/tunnel.c
+++ b/src/network/netdev/tunnel.c
@@ -51,14 +51,16 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
int r;
assert(netdev);
- assert(link);
assert(m);
assert(t);
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
- r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+
+ }
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
if (r < 0)
@@ -84,14 +86,16 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
int r;
assert(netdev);
- assert(link);
assert(m);
assert(t);
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
- r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+
+ }
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
if (r < 0)
@@ -125,12 +129,13 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
assert(t);
assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
- assert(link);
assert(m);
- r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
+ }
r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
if (r < 0)
@@ -168,12 +173,13 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl
assert(t);
assert(t->family == AF_INET6);
- assert(link);
assert(m);
- r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
+ }
r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
if (r < 0)
@@ -205,7 +211,6 @@ static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_me
Tunnel *t;
int r;
- assert(link);
assert(m);
if (netdev->kind == NETDEV_KIND_VTI)
@@ -243,9 +248,11 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink
assert(t);
assert(t->family == AF_INET);
- r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ }
r = netdev_vti_fill_message_key(netdev, link, m);
if (r < 0)
@@ -267,14 +274,15 @@ static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlin
int r;
assert(netdev);
- assert(link);
assert(m);
assert(t);
assert(t->family == AF_INET6);
- r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ }
r = netdev_vti_fill_message_key(netdev, link, m);
if (r < 0)
@@ -297,14 +305,15 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
int r;
assert(netdev);
- assert(link);
assert(m);
assert(t);
assert(t->family == AF_INET6);
- r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
- if (r < 0)
- return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ if (link) {
+ r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
+ }
r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
if (r < 0)
@@ -568,7 +577,7 @@ int config_parse_encap_limit(const char* unit,
const char *section,
unsigned section_line,
const char *lvalue,
- int ltype,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h
index d78c6135ee..53690d9075 100644
--- a/src/network/netdev/tunnel.h
+++ b/src/network/netdev/tunnel.h
@@ -60,6 +60,7 @@ typedef struct Tunnel {
bool pmtudisc;
bool copy_dscp;
+ bool independent;
} Tunnel;
DEFINE_NETDEV_CAST(IPIP, Tunnel);
diff --git a/src/network/netdev/vrf.c b/src/network/netdev/vrf.c
index f48b413102..a3b271ca23 100644
--- a/src/network/netdev/vrf.c
+++ b/src/network/netdev/vrf.c
@@ -35,7 +35,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink
assert(v);
- r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table_id);
+ r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IPLA_VRF_TABLE attribute: %m");
diff --git a/src/network/netdev/vrf.h b/src/network/netdev/vrf.h
index 00f54ed96d..06f3c17bc1 100644
--- a/src/network/netdev/vrf.h
+++ b/src/network/netdev/vrf.h
@@ -26,7 +26,7 @@ typedef struct Vrf Vrf;
struct Vrf {
NetDev meta;
- uint32_t table_id;
+ uint32_t table;
};
DEFINE_NETDEV_CAST(VRF, Vrf);
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 54d54c8fd5..e4b95e4195 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -383,7 +383,7 @@ static int get_gateway_description(
assert(rtnl);
assert(ifindex >= 0);
- assert(family == AF_INET || family == AF_INET6);
+ assert(IN_SET(family, AF_INET, AF_INET6));
assert(gateway);
assert(gateway_description);
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index d66b3a288f..214192ffe8 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -453,7 +453,7 @@ int address_remove(
int r;
assert(address);
- assert(address->family == AF_INET || address->family == AF_INET6);
+ assert(IN_SET(address->family, AF_INET, AF_INET6));
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
@@ -553,7 +553,7 @@ int address_configure(
int r;
assert(address);
- assert(address->family == AF_INET || address->family == AF_INET6);
+ assert(IN_SET(address->family, AF_INET, AF_INET6));
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
@@ -768,7 +768,7 @@ int config_parse_address(const char *unit,
}
if (!e && f == AF_INET) {
- r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
+ r = in4_addr_default_prefixlen(&buffer.in, &n->prefixlen);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
return 0;
@@ -927,6 +927,49 @@ int config_parse_address_flags(const char *unit,
return 0;
}
+int config_parse_address_scope(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Network *network = userdata;
+ _cleanup_address_free_ Address *n = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = address_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ if (streq(rvalue, "host"))
+ n->scope = RT_SCOPE_HOST;
+ else if (streq(rvalue, "link"))
+ n->scope = RT_SCOPE_LINK;
+ else if (streq(rvalue, "global"))
+ n->scope = RT_SCOPE_UNIVERSE;
+ else {
+ r = safe_atou8(rvalue , &n->scope);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
bool address_is_ready(const Address *a) {
assert(a);
@@ -1179,4 +1222,4 @@ int config_parse_prefix_lifetime(const char *unit,
p = NULL;
return 0;
-};
+}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 065328482e..3281c6d3c2 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -102,6 +102,7 @@ int config_parse_broadcast(const char *unit, const char *filename, unsigned line
int config_parse_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_lifetime(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_address_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_address_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_router_preference(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_prefix(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_prefix_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index e28e018116..025662437b 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -87,7 +87,7 @@ int config_parse_duid_rawdata(
}
len = strlen(cbyte);
- if (len != 1 && len != 2) {
+ if (!IN_SET(len, 1, 2)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
return 0;
}
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 9229b5753c..e1e3e88708 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -23,6 +23,7 @@
#include "alloc-util.h"
#include "dhcp-lease-internal.h"
#include "hostname-util.h"
+#include "netdev/vrf.h"
#include "network-internal.h"
#include "networkd-link.h"
#include "networkd-manager.h"
@@ -69,14 +70,25 @@ static int link_set_dhcp_routes(Link *link) {
struct in_addr gateway, address;
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
int r, n, i;
+ uint32_t table;
assert(link);
- assert(link->dhcp_lease);
- assert(link->network);
+
+ if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
+ return 0;
+
+ if (!link->network) /* link went down while we configured the IP addresses? */
+ return 0;
if (!link->network->dhcp_use_routes)
return 0;
+ /* When the interface is part of an VRF use the VRFs routing table, unless
+ * there is a another table specified. */
+ table = link->network->dhcp_route_table;
+ if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
+ table = VRF(link->network->vrf)->table;
+
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
@@ -109,7 +121,7 @@ static int link_set_dhcp_routes(Link *link) {
route_gw->scope = RT_SCOPE_LINK;
route_gw->protocol = RTPROT_DHCP;
route_gw->priority = link->network->dhcp_route_metric;
- route_gw->table = link->network->dhcp_route_table;
+ route_gw->table = table;
r = route_configure(route_gw, link, dhcp4_route_handler);
if (r < 0)
@@ -121,7 +133,7 @@ static int link_set_dhcp_routes(Link *link) {
route->gw.in = gateway;
route->prefsrc.in = address;
route->priority = link->network->dhcp_route_metric;
- route->table = link->network->dhcp_route_table;
+ route->table = table;
r = route_configure(route, link, dhcp4_route_handler);
if (r < 0) {
@@ -152,7 +164,7 @@ static int link_set_dhcp_routes(Link *link) {
assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
route->priority = link->network->dhcp_route_metric;
- route->table = link->network->dhcp_route_table;
+ route->table = table;
route->scope = route_scope_from_address(route, &address);
r = route_configure(route, link, dhcp4_route_handler);
@@ -233,7 +245,7 @@ static int dhcp_lease_lost(Link *link) {
if (r >= 0) {
r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
if (r >= 0)
- prefixlen = in_addr_netmask_to_prefixlen(&netmask);
+ prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
address->family = AF_INET;
address->in_addr.in = addr;
@@ -312,7 +324,7 @@ static int dhcp4_update_address(Link *link,
assert(netmask);
assert(lifetime);
- prefixlen = in_addr_netmask_to_prefixlen(netmask);
+ prefixlen = in4_addr_netmask_to_prefixlen(netmask);
r = address_new(&addr);
if (r < 0)
@@ -402,7 +414,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
- prefixlen = in_addr_netmask_to_prefixlen(&netmask);
+ prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
r = sd_dhcp_lease_get_router(lease, &gateway);
if (r < 0 && r != -ENODATA)
@@ -579,7 +591,7 @@ int dhcp4_configure(Link *link) {
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
if (!link->dhcp_client) {
- r = sd_dhcp_client_new(&link->dhcp_client);
+ r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0)
return r;
}
@@ -620,7 +632,12 @@ int dhcp4_configure(Link *link) {
return r;
}
- if (link->network->dhcp_use_routes) {
+ /* NOTE: when using Anonymity Profiles, routes PRL options are sent
+ * by default, so they should not be added again here. */
+ /* NOTE: even if this variable is called "use", it also "sends" PRL
+ * options, maybe there should be a different configuration variable
+ * to send or not route options?. */
+ if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
r = sd_dhcp_client_set_request_option(link->dhcp_client,
SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
@@ -631,14 +648,17 @@ int dhcp4_configure(Link *link) {
return r;
}
- /* Always acquire the timezone and NTP */
- r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
- if (r < 0)
- return r;
+ if (link->network->dhcp_use_ntp) {
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
+ if (r < 0)
+ return r;
+ }
- r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
- if (r < 0)
- return r;
+ if (link->network->dhcp_use_timezone) {
+ r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
+ if (r < 0)
+ return r;
+ }
r = dhcp4_set_hostname(link);
if (r < 0)
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 4c57fa1793..6b591271a0 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -33,6 +33,7 @@
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-radv.h"
+#include "networkd-routing-policy-rule.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -497,8 +498,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
static void link_free(Link *link) {
Address *address;
- Iterator i;
Link *carrier;
+ Iterator i;
if (!link)
return;
@@ -1014,6 +1015,7 @@ static int link_set_bridge_fdb(Link *link) {
}
static int link_enter_set_addresses(Link *link) {
+ RoutingPolicyRule *rule, *rrule = NULL;
AddressLabel *label;
Address *ad;
int r;
@@ -1050,6 +1052,26 @@ static int link_enter_set_addresses(Link *link) {
link->link_messages++;
}
+ LIST_FOREACH(rules, rule, link->network->rules) {
+ r = routing_policy_rule_get(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
+ rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, &rrule);
+ if (r == 1) {
+ (void) routing_policy_rule_make_local(link->manager, rrule);
+ continue;
+ }
+
+ r = routing_policy_rule_configure(rule, link, link_routing_policy_rule_handler, false);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not set routing policy rules: %m");
+ link_enter_failed(link);
+ return r;
+ }
+
+ link->link_messages++;
+ }
+
+ routing_policy_rule_purge(link->manager, link);
+
/* now that we can figure out a default address for the dhcp server,
start it */
if (link_dhcp4_server_enabled(link)) {
@@ -2138,7 +2160,7 @@ static int link_joined(Link *link) {
/* Skip setting up addresses until it gets carrier,
or it would try to set addresses twice,
which is bad for non-idempotent steps. */
- if (!link_has_carrier(link))
+ if (!link_has_carrier(link) && !link->network->configure_without_carrier)
return 0;
return link_enter_set_addresses(link);
@@ -2647,7 +2669,7 @@ static int link_configure(Link *link) {
return r;
}
- if (link_has_carrier(link)) {
+ if (link_has_carrier(link) || link->network->configure_without_carrier) {
r = link_acquire_conf(link);
if (r < 0)
return r;
@@ -2916,7 +2938,7 @@ network_file_fail:
goto dhcp4_address_fail;
}
- r = sd_dhcp_client_new(&link->dhcp_client);
+ r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0)
return log_link_error_errno(link, r, "Failed to create DHCPv4 client: %m");
@@ -3186,8 +3208,6 @@ int link_update(Link *link, sd_netlink_message *m) {
}
if (link->dhcp_client) {
- const DUID *duid = link_duid(link);
-
r = sd_dhcp_client_set_mac(link->dhcp_client,
(const uint8_t *) &link->mac,
sizeof (link->mac),
@@ -3195,13 +3215,30 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
- r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
- link->network->iaid,
- duid->type,
- duid->raw_data_len > 0 ? duid->raw_data : NULL,
- duid->raw_data_len);
- if (r < 0)
- return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
+ switch (link->network->dhcp_client_identifier) {
+ case DHCP_CLIENT_ID_DUID: {
+ const DUID *duid = link_duid(link);
+
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
+ break;
+ }
+ case DHCP_CLIENT_ID_MAC:
+ r = sd_dhcp_client_set_client_id(link->dhcp_client,
+ ARPHRD_ETHER,
+ (const uint8_t *)&link->mac,
+ sizeof(link->mac));
+ if(r < 0)
+ return log_link_warning_errno(link, r, "Could not update MAC client id in DHCP client: %m");
+ break;
+ default:
+ assert_not_reached("Unknown client identifier type.");
+ }
}
if (link->dhcp6_client) {
@@ -3276,16 +3313,16 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
if (hashmap_isempty(h))
return;
- fputs(prefix, f);
+ fputs_unlocked(prefix, f);
HASHMAP_FOREACH(link, h, i) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
fprintf(f, "%i", link->ifindex);
space = true;
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
int link_save(Link *link) {
@@ -3343,7 +3380,7 @@ int link_save(Link *link) {
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
- fputs("DNS=", f);
+ fputs_unlocked("DNS=", f);
space = false;
for (j = 0; j < link->network->n_dns; j++) {
@@ -3357,8 +3394,8 @@ int link_save(Link *link) {
}
if (space)
- fputc(' ', f);
- fputs(b, f);
+ fputc_unlocked(' ', f);
+ fputs_unlocked(b, f);
space = true;
}
@@ -3369,7 +3406,7 @@ int link_save(Link *link) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
serialize_in_addrs(f, addresses, r);
space = true;
}
@@ -3381,7 +3418,7 @@ int link_save(Link *link) {
r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs);
if (r > 0) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
serialize_in6_addrs(f, in6_addrs, r);
space = true;
}
@@ -3395,16 +3432,16 @@ int link_save(Link *link) {
SET_FOREACH(dd, link->ndisc_rdnss, i) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
serialize_in6_addrs(f, &dd->address, 1);
space = true;
}
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
- fputs("NTP=", f);
+ fputs_unlocked("NTP=", f);
space = false;
fputstrv(f, link->network->ntp, NULL, &space);
@@ -3415,7 +3452,7 @@ int link_save(Link *link) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
serialize_in_addrs(f, addresses, r);
space = true;
}
@@ -3429,7 +3466,7 @@ int link_save(Link *link) {
&in6_addrs);
if (r > 0) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
serialize_in6_addrs(f, in6_addrs, r);
space = true;
}
@@ -3439,7 +3476,7 @@ int link_save(Link *link) {
fputstrv(f, hosts, NULL, &space);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease) {
@@ -3450,7 +3487,7 @@ int link_save(Link *link) {
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
- fputs("DOMAINS=", f);
+ fputs_unlocked("DOMAINS=", f);
space = false;
fputstrv(f, link->network->search_domains, NULL, &space);
@@ -3468,9 +3505,9 @@ int link_save(Link *link) {
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
- fputs("ROUTE_DOMAINS=", f);
+ fputs_unlocked("ROUTE_DOMAINS=", f);
space = false;
fputstrv(f, link->network->route_domains, NULL, &space);
@@ -3488,7 +3525,7 @@ int link_save(Link *link) {
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
@@ -3502,14 +3539,14 @@ int link_save(Link *link) {
if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
const char *n;
- fputs("DNSSEC_NTA=", f);
+ fputs_unlocked("DNSSEC_NTA=", f);
space = false;
SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i)
fputs_with_space(f, n, NULL, &space);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
- fputs("ADDRESSES=", f);
+ fputs_unlocked("ADDRESSES=", f);
space = false;
SET_FOREACH(a, link->addresses, i) {
_cleanup_free_ char *address_str = NULL;
@@ -3521,9 +3558,9 @@ int link_save(Link *link) {
fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
space = true;
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
- fputs("ROUTES=", f);
+ fputs_unlocked("ROUTES=", f);
space = false;
SET_FOREACH(route, link->routes, i) {
_cleanup_free_ char *route_str = NULL;
@@ -3537,7 +3574,7 @@ int link_save(Link *link) {
space = true;
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
@@ -3555,9 +3592,9 @@ int link_save(Link *link) {
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r >= 0) {
- fputs("DHCP4_ADDRESS=", f);
+ fputs_unlocked("DHCP4_ADDRESS=", f);
serialize_in_addrs(f, &address, 1);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
@@ -3575,9 +3612,9 @@ int link_save(Link *link) {
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
if (r >= 0) {
- fputs("IPV4LL_ADDRESS=", f);
+ fputs_unlocked("IPV4LL_ADDRESS=", f);
serialize_in_addrs(f, &address, 1);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
}
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 5f10b4f993..71445d5dda 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -19,6 +19,7 @@
#include <sys/socket.h>
#include <linux/if.h>
+#include <linux/fib_rules.h>
#include "sd-daemon.h"
#include "sd-netlink.h"
@@ -47,7 +48,7 @@ const char* const network_dirs[] = {
"/etc/systemd/network",
"/run/systemd/network",
"/usr/lib/systemd/network",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib/systemd/network",
#endif
NULL};
@@ -136,10 +137,9 @@ int manager_connect_bus(Manager *m) {
assert(m);
r = sd_bus_default_system(&m->bus);
- if (r == -ENOENT) {
+ if (r < 0) {
/* We failed to connect? Yuck, we must be in early
- * boot. Let's try in 5s again. As soon as we have
- * kdbus we can stop doing this... */
+ * boot. Let's try in 5s again. */
log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
@@ -296,7 +296,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
Link *link = NULL;
uint16_t type;
uint32_t ifindex, priority = 0;
- unsigned char protocol, scope, tos, table;
+ unsigned char protocol, scope, tos, table, rt_type;
int family;
unsigned char dst_prefixlen, src_prefixlen;
union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
@@ -319,7 +319,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type: %m");
return 0;
- } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+ } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
log_warning("rtnl: received unexpected message type when processing route");
return 0;
}
@@ -413,7 +413,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
break;
default:
- log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+ assert_not_reached("Received unsupported address family");
return 0;
}
@@ -441,6 +441,12 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
return 0;
}
+ r = sd_rtnl_message_route_get_type(message, &rt_type);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid type, ignoring: %m");
+ return 0;
+ }
+
r = sd_rtnl_message_route_get_table(message, &table);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
@@ -464,7 +470,7 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
return 0;
}
- route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol);
+ route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, rt_type, protocol);
break;
@@ -510,7 +516,7 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
if (r < 0) {
log_warning_errno(r, "rtnl: could not get message type: %m");
return 0;
- } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+ } else if (!IN_SET(type, RTM_NEWADDR, RTM_DELADDR)) {
log_warning("rtnl: received unexpected message type when processing address");
return 0;
}
@@ -657,7 +663,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
if (r < 0) {
log_warning_errno(r, "rtnl: Could not get message type: %m");
return 0;
- } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
+ } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
log_warning("rtnl: Received unexpected message type when processing link");
return 0;
}
@@ -719,6 +725,116 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa
return 1;
}
+int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0;
+ RoutingPolicyRule *rule = NULL;
+ union in_addr_union to, from;
+ uint32_t fwmark = 0, table = 0;
+ Manager *m = userdata;
+ uint16_t type;
+ int family;
+ int r;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive rule: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
+ log_warning("rtnl: received unexpected message type '%u' when processing rule.", type);
+ return 0;
+ }
+
+ r = sd_rtnl_message_get_family(message, &family);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get rule family: %m");
+ return 0;
+ } else if (!IN_SET(family, AF_INET, AF_INET6)) {
+ log_debug("rtnl: received address with invalid family %u, ignoring.", family);
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, FRA_SRC, &from.in);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
+ }
+
+ r = sd_netlink_message_read_in_addr(message, FRA_DST, &to.in);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &from.in6);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &from_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule from prefix length: %m");
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, FRA_DST, &to.in6);
+ if (r >= 0) {
+ r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &to_prefixlen);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to retrive rule to prefix length: %m");
+ }
+
+ break;
+
+ default:
+ assert_not_reached("Received unsupported address family");
+ }
+
+ if (from_prefixlen == 0 && to_prefixlen == 0)
+ return 0;
+
+ (void) sd_netlink_message_read_u32(message, FRA_FWMARK, &fwmark);
+ (void) sd_netlink_message_read_u32(message, FRA_TABLE, &table);
+ (void) sd_rtnl_message_routing_policy_rule_get_tos(message, &tos);
+
+ (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
+
+ switch (type) {
+ case RTM_NEWRULE:
+ if(!rule) {
+ r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, &rule);
+ if (r < 0) {
+ log_warning_errno(r, "Could not add rule: %m");
+ return 0;
+ }
+ }
+ break;
+ case RTM_DELRULE:
+ routing_policy_rule_free(rule);
+
+ break;
+
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
static int systemd_netlink_fd(void) {
int n, fd, rtnl_fd = -EINVAL;
@@ -783,6 +899,14 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWRULE, &manager_rtnl_process_rule, m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, RTM_DELRULE, &manager_rtnl_process_rule, m);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -866,16 +990,18 @@ static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
if (ordered_set_isempty(s))
return;
- fputs(field, f);
+ fputs_unlocked(field, f);
ORDERED_SET_FOREACH(p, s, i)
fputs_with_space(f, p, NULL, &space);
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
static int manager_save(Manager *m) {
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
+ RoutingPolicyRule *rule = NULL;
+ bool space = false;
Link *link;
Iterator i;
_cleanup_free_ char *temp_path = NULL;
@@ -1000,6 +1126,28 @@ static int manager_save(Manager *m) {
print_string_set(f, "DOMAINS=", search_domains);
print_string_set(f, "ROUTE_DOMAINS=", route_domains);
+ SET_FOREACH(rule, m->rules, i) {
+ _cleanup_free_ char *from_str = NULL, *to_str = NULL;
+ fputs("RULE=", f);
+
+ if (!in_addr_is_null(rule->family, &rule->from)) {
+ r = in_addr_to_string(rule->family, &rule->from, &from_str);
+ if (r < 0)
+ goto fail;
+ }
+
+ if (!in_addr_is_null(rule->family, &rule->to)) {
+ r = in_addr_to_string(rule->family, &rule->to, &to_str);
+ if (r < 0)
+ goto fail;
+ }
+
+ fprintf(f, "from=%s%s/%hhu to=%s%s/%hhu tos=%hhu fwmark=%"PRIu32"/%"PRIu32" table=%hhu", space ? " " : "", from_str,
+ rule->from_prefixlen, space ? " " : "", to_str, rule->to_prefixlen, rule->tos, rule->fwmark, rule->fwmask, rule->table);
+
+ fputc('\n', f);
+ }
+
r = fflush_and_check(f);
if (r < 0)
goto fail;
@@ -1085,6 +1233,8 @@ int manager_new(Manager **ret, sd_event *event) {
m->duid.type = DUID_TYPE_EN;
+ (void) routing_policy_rule_load(m);
+
*ret = m;
m = NULL;
@@ -1092,6 +1242,7 @@ int manager_new(Manager **ret, sd_event *event) {
}
void manager_free(Manager *m) {
+ RoutingPolicyRule *rule;
Network *network;
NetDev *netdev;
Link *link;
@@ -1102,13 +1253,13 @@ void manager_free(Manager *m) {
free(m->state_file);
+ while ((network = m->networks))
+ network_free(network);
+
while ((link = hashmap_first(m->links)))
link_unref(link);
hashmap_free(m->links);
- while ((network = m->networks))
- network_free(network);
-
hashmap_free(m->networks_by_name);
while ((netdev = hashmap_first(m->netdevs)))
@@ -1118,6 +1269,14 @@ void manager_free(Manager *m) {
while ((pool = m->address_pools))
address_pool_free(pool);
+ set_free(m->rules);
+ set_free(m->rules_foreign);
+
+ while ((rule = set_steal_first(m->rules_saved)))
+ free(rule);
+
+ set_free(m->rules_saved);
+
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
@@ -1278,6 +1437,41 @@ int manager_rtnl_enumerate_routes(Manager *m) {
return r;
}
+int manager_rtnl_enumerate_rules(Manager *m) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ sd_netlink_message *rule;
+ int r;
+
+ assert(m);
+ assert(m->rtnl);
+
+ r = sd_rtnl_message_new_routing_policy_rule(m->rtnl, &req, RTM_GETRULE, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(m->rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (rule = reply; rule; rule = sd_netlink_message_next(rule)) {
+ int k;
+
+ m->enumerating = true;
+
+ k = manager_rtnl_process_rule(m->rtnl, rule, m);
+ if (k < 0)
+ r = k;
+
+ m->enumerating = false;
+ }
+
+ return r;
+}
+
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
AddressPool *p;
int r;
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index e2447c2230..254aab8452 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -65,6 +65,10 @@ struct Manager {
DUID duid;
char* dynamic_hostname;
char* dynamic_timezone;
+
+ Set *rules;
+ Set *rules_foreign;
+ Set *rules_saved;
};
static inline const DUID* link_duid(const Link *link) {
@@ -88,9 +92,11 @@ bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
int manager_rtnl_enumerate_routes(Manager *m);
+int manager_rtnl_enumerate_rules(Manager *m);
int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+int manager_rtnl_process_rule(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
void manager_dirty(Manager *m);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index a2d38501a5..af39d77ce9 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -70,6 +70,7 @@ Network.IPv4ProxyARP, config_parse_tristate,
Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address, 0, 0
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
+Network.ConfigureWithoutCarrier, config_parse_bool, 0, offsetof(Network, configure_without_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
Address.Broadcast, config_parse_broadcast, 0, 0
@@ -80,8 +81,15 @@ Address.DuplicateAddressDetection, config_parse_address_flags,
Address.ManageTemporaryAddress, config_parse_address_flags, 0, 0
Address.PrefixRoute, config_parse_address_flags, 0, 0
Address.AutoJoin, config_parse_address_flags, 0, 0
+Address.Scope, config_parse_address_scope, 0, 0
IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 0, 0
IPv6AddressLabel.Label, config_parse_address_label, 0, 0
+RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule_tos, 0, 0
+RoutingPolicyRule.Priority, config_parse_routing_policy_rule_priority, 0, 0
+RoutingPolicyRule.Table, config_parse_routing_policy_rule_table, 0, 0
+RoutingPolicyRule.FirewallMark, config_parse_routing_policy_rule_fwmark_mask, 0, 0
+RoutingPolicyRule.From, config_parse_routing_policy_rule_prefix, 0, 0
+RoutingPolicyRule.To, config_parse_routing_policy_rule_prefix, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
Route.Source, config_parse_destination, 0, 0
@@ -92,6 +100,7 @@ Route.Table, config_parse_route_table,
Route.GatewayOnlink, config_parse_gateway_onlink, 0, 0
Route.IPv6Preference, config_parse_ipv6_route_preference, 0, 0
Route.Protocol, config_parse_route_protocol, 0, 0
+Route.Type, config_parse_route_type, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
@@ -99,6 +108,7 @@ DHCP.UseMTU, config_parse_bool,
DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname)
DHCP.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains)
DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes)
+DHCP.Anonymize, config_parse_bool, 0, offsetof(Network, dhcp_anonymize)
DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname)
DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
@@ -107,7 +117,7 @@ DHCP.VendorClassIdentifier, config_parse_string,
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
-DHCP.RouteTable, config_parse_dhcp_route_table, 0, offsetof(Network, dhcp_route_table)
+DHCP.RouteTable, config_parse_dhcp_route_table, 0, 0
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
@@ -142,6 +152,9 @@ IPv6PrefixDelegation.RouterLifetimeSec, config_parse_sec,
IPv6PrefixDelegation.Managed, config_parse_bool, 0, offsetof(Network, router_managed)
IPv6PrefixDelegation.OtherInformation, config_parse_bool, 0, offsetof(Network, router_other_information)
IPv6PrefixDelegation.RouterPreference, config_parse_router_preference, 0, 0
+IPv6PrefixDelegation.DNS, config_parse_radv_dns, 0, 0
+IPv6PrefixDelegation.Domains, config_parse_radv_search_domains, 0, 0
+IPv6PrefixDelegation.DNSLifetimeSec, config_parse_sec, 0, offsetof(Network, router_dns_lifetime_usec)
IPv6Prefix.Prefix, config_parse_prefix, 0, 0
IPv6Prefix.OnLink, config_parse_prefix_flags, 0, 0
IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_flags, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 6f2ae66d40..3a7eb2c2a8 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -26,6 +26,7 @@
#include "dns-domain.h"
#include "fd-util.h"
#include "hostname-util.h"
+#include "in-addr-util.h"
#include "network-internal.h"
#include "networkd-manager.h"
#include "networkd-network.h"
@@ -34,6 +35,7 @@
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "util.h"
static void network_config_hash_func(const void *p, struct siphash *state) {
@@ -76,7 +78,47 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi
}
void network_config_section_free(NetworkConfigSection *cs) {
- free(cs);
+ free(cs);
+}
+
+/* Set defaults following RFC7844 */
+void network_apply_anonymize_if_set(Network *network) {
+ if (!network->dhcp_anonymize)
+ return;
+ /* RFC7844 3.7
+ SHOULD NOT send the Host Name option */
+ network->dhcp_send_hostname = false;
+ /* RFC7844 section 3.:
+ MAY contain the Client Identifier option
+ Section 3.5:
+ clients MUST use client identifiers based solely
+ on the link-layer address */
+ /* NOTE: Using MAC, as it does not reveal extra information,
+ * and some servers might not answer if this option is not sent */
+ network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
+ /* RFC 7844 3.10:
+ SHOULD NOT use the Vendor Class Identifier option */
+ /* NOTE: it was not initiallized to any value in network_load_one. */
+ network->dhcp_vendor_class_identifier = false;
+ /* RFC7844 section 3.6.:
+ The client intending to protect its privacy SHOULD only request a
+ minimal number of options in the PRL and SHOULD also randomly shuffle
+ the ordering of option codes in the PRL. If this random ordering
+ cannot be implemented, the client MAY order the option codes in the
+ PRL by option code number (lowest to highest).
+ */
+ /* NOTE: dhcp_use_mtu is false by default,
+ * though it was not initiallized to any value in network_load_one.
+ * Maybe there should be another var called *send*?
+ * (to use the MTU sent by the server but to do not send
+ * the option in the PRL). */
+ network->dhcp_use_mtu = false;
+ /* RFC7844 section 3.6.
+ * same comments as previous option */
+ network->dhcp_use_routes = false;
+ /* RFC7844 section 3.6.
+ * same comments as previous option */
+ network->dhcp_use_timezone = false;
}
static int network_load_one(Manager *manager, const char *filename) {
@@ -116,6 +158,7 @@ static int network_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
LIST_HEAD_INIT(network->address_labels);
LIST_HEAD_INIT(network->static_prefixes);
+ LIST_HEAD_INIT(network->rules);
network->stacked_netdevs = hashmap_new(&string_hash_ops);
if (!network->stacked_netdevs)
@@ -141,6 +184,10 @@ static int network_load_one(Manager *manager, const char *filename) {
if (!network->prefixes_by_section)
return log_oom();
+ network->rules_by_section = hashmap_new(&network_config_hash_ops);
+ if (!network->rules_by_section)
+ return log_oom();
+
network->filename = strdup(filename);
if (!network->filename)
return log_oom();
@@ -161,11 +208,25 @@ static int network_load_one(Manager *manager, const char *filename) {
network->dhcp_use_ntp = true;
network->dhcp_use_dns = true;
network->dhcp_use_hostname = true;
+ /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
network->dhcp_use_routes = true;
+ /* NOTE: this var might be overwriten by network_apply_anonymize_if_set */
network->dhcp_send_hostname = true;
+ /* To enable/disable RFC7844 Anonymity Profiles */
+ network->dhcp_anonymize = false;
network->dhcp_route_metric = DHCP_ROUTE_METRIC;
+ /* NOTE: this var might be overwrite by network_apply_anonymize_if_set */
network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID;
network->dhcp_route_table = RT_TABLE_MAIN;
+ network->dhcp_route_table_set = false;
+ /* NOTE: the following vars were not set to any default,
+ * even if they are commented in the man?
+ * These vars might be overwriten by network_apply_anonymize_if_set */
+ network->dhcp_vendor_class_identifier = false;
+ /* NOTE: from man: UseMTU=... Defaults to false*/
+ network->dhcp_use_mtu = false;
+ /* NOTE: from man: UseTimezone=... Defaults to "no".*/
+ network->dhcp_use_timezone = false;
network->dhcp_server_emit_dns = true;
network->dhcp_server_emit_ntp = true;
@@ -204,6 +265,7 @@ static int network_load_one(Manager *manager, const char *filename) {
"Network\0"
"Address\0"
"IPv6AddressLabel\0"
+ "RoutingPolicyRule\0"
"Route\0"
"DHCP\0"
"DHCPv4\0" /* compat */
@@ -220,6 +282,8 @@ static int network_load_one(Manager *manager, const char *filename) {
if (r < 0)
return r;
+ network_apply_anonymize_if_set(network);
+
/* IPMasquerade=yes implies IPForward=yes */
if (network->ip_masquerade)
network->ip_forward |= ADDRESS_FAMILY_IPV4;
@@ -266,7 +330,7 @@ int network_load(Manager *manager) {
while ((network = manager->networks))
network_free(network);
- r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
+ r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate network files: %m");
@@ -280,13 +344,14 @@ int network_load(Manager *manager) {
}
void network_free(Network *network) {
- NetDev *netdev;
- Route *route;
- Address *address;
- FdbEntry *fdb_entry;
IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
+ RoutingPolicyRule *rule;
+ FdbEntry *fdb_entry;
AddressLabel *label;
Prefix *prefix;
+ Address *address;
+ NetDev *netdev;
+ Route *route;
Iterator i;
if (!network)
@@ -340,11 +405,15 @@ void network_free(Network *network) {
while ((prefix = network->static_prefixes))
prefix_free(prefix);
+ while ((rule = network->rules))
+ routing_policy_rule_free(rule);
+
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
hashmap_free(network->fdb_entries_by_section);
hashmap_free(network->address_labels_by_section);
hashmap_free(network->prefixes_by_section);
+ hashmap_free(network->rules_by_section);
if (network->manager) {
if (network->manager->networks)
@@ -681,16 +750,16 @@ int config_parse_tunnel(const char *unit,
return 0;
}
- if (netdev->kind != NETDEV_KIND_IPIP &&
- netdev->kind != NETDEV_KIND_SIT &&
- netdev->kind != NETDEV_KIND_GRE &&
- netdev->kind != NETDEV_KIND_GRETAP &&
- netdev->kind != NETDEV_KIND_IP6GRE &&
- netdev->kind != NETDEV_KIND_IP6GRETAP &&
- netdev->kind != NETDEV_KIND_VTI &&
- netdev->kind != NETDEV_KIND_VTI6 &&
- netdev->kind != NETDEV_KIND_IP6TNL
- ) {
+ if (!IN_SET(netdev->kind,
+ NETDEV_KIND_IPIP,
+ NETDEV_KIND_SIT,
+ NETDEV_KIND_GRE,
+ NETDEV_KIND_GRETAP,
+ NETDEV_KIND_IP6GRE,
+ NETDEV_KIND_IP6GRETAP,
+ NETDEV_KIND_VTI,
+ NETDEV_KIND_VTI6,
+ NETDEV_KIND_IP6TNL)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"NetDev is not a tunnel, ignoring assignment: %s", rvalue);
return 0;
@@ -787,8 +856,8 @@ static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
[DHCP_CLIENT_ID_DUID] = "duid"
};
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type");
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
int config_parse_ipv6token(
const char* unit,
@@ -1008,6 +1077,107 @@ int config_parse_dhcp_server_dns(
return 0;
}
+int config_parse_radv_dns(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *n = data;
+ const char *p = rvalue;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+ union in_addr_union a;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
+
+ if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
+ struct in6_addr *m;
+
+ m = realloc(n->router_dns, (n->n_router_dns + 1) * sizeof(struct in6_addr));
+ if (!m)
+ return log_oom();
+
+ m[n->n_router_dns++] = a.in6;
+ n->router_dns = m;
+
+ } else
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
+
+ }
+
+ return 0;
+}
+
+int config_parse_radv_search_domains(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *n = data;
+ const char *p = rvalue;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+ _cleanup_free_ char *idna = NULL;
+
+ r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
+
+ r = dns_name_apply_idna(w, &idna);
+ if (r > 0) {
+ r = strv_push(&n->router_search_domains, idna);
+ if (r >= 0)
+ idna = NULL;
+ } else if (r == 0) {
+ r = strv_push(&n->router_search_domains, w);
+ if (r >= 0)
+ w = NULL;
+ }
+ }
+
+ return 0;
+}
+
int config_parse_dhcp_server_ntp(
const char *unit,
const char *filename,
@@ -1231,6 +1401,7 @@ int config_parse_dhcp_route_table(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
+ Network *network = data;
uint32_t rt;
int r;
@@ -1246,7 +1417,8 @@ int config_parse_dhcp_route_table(const char *unit,
return 0;
}
- *((uint32_t *)data) = rt;
+ network->dhcp_route_table = rt;
+ network->dhcp_route_table_set = true;
return 0;
}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index b31921947d..9fb0eae380 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -34,6 +34,7 @@
#include "networkd-lldp-tx.h"
#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-route.h"
+#include "networkd-routing-policy-rule.h"
#include "networkd-util.h"
#include "netdev/netdev.h"
@@ -43,12 +44,12 @@
#define BRIDGE_VLAN_BITMAP_MAX 4096
#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)
-typedef enum DCHPClientIdentifier {
+typedef enum DHCPClientIdentifier {
DHCP_CLIENT_ID_MAC,
DHCP_CLIENT_ID_DUID,
_DHCP_CLIENT_ID_MAX,
_DHCP_CLIENT_ID_INVALID = -1,
-} DCHPClientIdentifier;
+} DHCPClientIdentifier;
typedef enum IPv6PrivacyExtensions {
/* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
@@ -122,12 +123,13 @@ struct Network {
/* DHCP Client Support */
AddressFamilyBoolean dhcp;
- DCHPClientIdentifier dhcp_client_identifier;
+ DHCPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
char *dhcp_hostname;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
uint16_t dhcp_client_port;
+ bool dhcp_anonymize;
bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_critical;
@@ -137,6 +139,7 @@ struct Network {
bool dhcp_use_routes;
bool dhcp_use_timezone;
bool dhcp_use_hostname;
+ bool dhcp_route_table_set;
DHCPUseDomains dhcp_use_domains;
/* DHCP Server Support */
@@ -164,6 +167,10 @@ struct Network {
uint8_t router_preference;
bool router_managed;
bool router_other_information;
+ usec_t router_dns_lifetime_usec;
+ struct in6_addr *router_dns;
+ unsigned n_router_dns;
+ char **router_search_domains;
/* Bridge Support */
bool use_bpdu;
@@ -201,6 +208,7 @@ struct Network {
size_t mtu;
int arp;
bool unmanaged;
+ bool configure_without_carrier;
uint32_t iaid;
DUID duid;
@@ -213,6 +221,7 @@ struct Network {
LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
LIST_HEAD(AddressLabel, address_labels);
LIST_HEAD(Prefix, static_prefixes);
+ LIST_HEAD(RoutingPolicyRule, rules);
unsigned n_static_addresses;
unsigned n_static_routes;
@@ -220,12 +229,14 @@ struct Network {
unsigned n_ipv6_proxy_ndp_addresses;
unsigned n_address_labels;
unsigned n_static_prefixes;
+ unsigned n_rules;
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
Hashmap *address_labels_by_section;
Hashmap *prefixes_by_section;
+ Hashmap *rules_by_section;
struct in_addr_data *dns;
unsigned n_dns;
@@ -250,6 +261,7 @@ int network_load(Manager *manager);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
int network_apply(Network *network, Link *link);
+void network_apply_anonymize_if_set(Network *network);
bool network_has_static_ipv6_addresses(Network *network);
@@ -264,6 +276,8 @@ int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename,
int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_radv_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_radv_search_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index af9e116936..6768208cfa 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -75,5 +75,24 @@ int radv_configure(Link *link) {
return r;
}
+ if (link->network->router_dns) {
+ r = sd_radv_set_rdnss(link->radv,
+ DIV_ROUND_UP(link->network->router_dns_lifetime_usec,
+ USEC_PER_SEC),
+ link->network->router_dns,
+ link->network->n_router_dns);
+ if (r < 0)
+ return r;
+ }
+
+ if (link->network->router_search_domains) {
+ r = sd_radv_set_dnssl(link->radv,
+ DIV_ROUND_UP(link->network->router_dns_lifetime_usec,
+ USEC_PER_SEC),
+ link->network->router_search_domains);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index e5d61ce8cc..cf42037915 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -70,6 +70,7 @@ int route_new(Route **ret) {
route->family = AF_UNSPEC;
route->scope = RT_SCOPE_UNIVERSE;
route->protocol = RTPROT_UNSPEC;
+ route->type = RTN_UNICAST;
route->table = RT_TABLE_MAIN;
route->lifetime = USEC_INFINITY;
@@ -372,7 +373,8 @@ int route_update(Route *route,
const union in_addr_union *gw,
const union in_addr_union *prefsrc,
unsigned char scope,
- unsigned char protocol) {
+ unsigned char protocol,
+ unsigned char type) {
assert(route);
assert(src);
@@ -385,6 +387,7 @@ int route_update(Route *route,
route->prefsrc = *prefsrc;
route->scope = scope;
route->protocol = protocol;
+ route->type = type;
return 0;
}
@@ -398,7 +401,7 @@ int route_remove(Route *route, Link *link,
assert(link->manager);
assert(link->manager->rtnl);
assert(link->ifindex > 0);
- assert(route->family == AF_INET || route->family == AF_INET6);
+ assert(IN_SET(route->family, AF_INET, AF_INET6));
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
RTM_DELROUTE, route->family,
@@ -458,9 +461,15 @@ int route_remove(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
- r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+ r = sd_rtnl_message_route_set_type(req, route->type);
if (r < 0)
- return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+ return log_error_errno(r, "Could not set route type: %m");
+
+ if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
+ r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+ }
r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
if (r < 0)
@@ -519,7 +528,7 @@ int route_configure(
assert(link->manager);
assert(link->manager->rtnl);
assert(link->ifindex > 0);
- assert(route->family == AF_INET || route->family == AF_INET6);
+ assert(IN_SET(route->family, AF_INET, AF_INET6));
if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
set_size(link->routes) >= routes_max())
@@ -612,9 +621,15 @@ int route_configure(
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
- r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+ r = sd_rtnl_message_route_set_type(req, route->type);
if (r < 0)
- return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+ return log_error_errno(r, "Could not set route type: %m");
+
+ if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
+ r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+ }
r = sd_netlink_message_open_container(req, RTA_METRICS);
if (r < 0)
@@ -1023,3 +1038,39 @@ int config_parse_route_protocol(const char *unit,
return 0;
}
+
+int config_parse_route_type(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Network *network = userdata;
+ _cleanup_route_free_ Route *n = NULL;
+ int r;
+
+ r = route_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ if (streq(rvalue, "unicast"))
+ n->type = RTN_UNICAST;
+ else if (streq(rvalue, "blackhole"))
+ n->type = RTN_BLACKHOLE;
+ else if (streq(rvalue, "unreachable"))
+ n->type = RTN_UNREACHABLE;
+ else if (streq(rvalue, "prohibit"))
+ n->type = RTN_PROHIBIT;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ n = NULL;
+
+ return 0;
+}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 3f389489da..89d32e9214 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -35,6 +35,7 @@ struct Route {
unsigned char src_prefixlen;
unsigned char scope;
unsigned char protocol; /* RTPROT_* */
+ unsigned char type; /* RTN_* */
unsigned char tos;
uint32_t priority; /* note that ip(8) calls this 'metric' */
uint32_t table;
@@ -62,7 +63,7 @@ int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback
int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, uint32_t table, Route **ret);
-int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
+int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol, unsigned char type);
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
@@ -78,3 +79,4 @@ int config_parse_route_table(const char *unit, const char *filename, unsigned li
int config_parse_gateway_onlink(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_ipv6_route_preference(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_protocol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_route_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c
new file mode 100644
index 0000000000..6850135fc1
--- /dev/null
+++ b/src/network/networkd-routing-policy-rule.c
@@ -0,0 +1,900 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Susant Sahani
+
+ 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 <net/if.h>
+#include <linux/fib_rules.h>
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "fileio.h"
+#include "networkd-routing-policy-rule.h"
+#include "netlink-util.h"
+#include "networkd-manager.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+
+int routing_policy_rule_new(RoutingPolicyRule **ret) {
+ RoutingPolicyRule *rule;
+
+ rule = new0(RoutingPolicyRule, 1);
+ if (!rule)
+ return -ENOMEM;
+
+ rule->family = AF_INET;
+ rule->table = RT_TABLE_MAIN;
+
+ *ret = rule;
+ return 0;
+}
+
+void routing_policy_rule_free(RoutingPolicyRule *rule) {
+
+ if (!rule)
+ return;
+
+ if (rule->network) {
+ LIST_REMOVE(rules, rule->network->rules, rule);
+ assert(rule->network->n_rules > 0);
+ rule->network->n_rules--;
+
+ if (rule->section) {
+ hashmap_remove(rule->network->rules_by_section, rule->section);
+ network_config_section_free(rule->section);
+ }
+
+ if (rule->network->manager) {
+ set_remove(rule->network->manager->rules, rule);
+ set_remove(rule->network->manager->rules_foreign, rule);
+ }
+ }
+
+ free(rule);
+}
+
+static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
+ const RoutingPolicyRule *rule = b;
+
+ assert(rule);
+
+ siphash24_compress(&rule->family, sizeof(rule->family), state);
+
+ switch (rule->family) {
+ case AF_INET:
+ case AF_INET6:
+
+ siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
+ siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
+
+ siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
+ siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
+
+ siphash24_compress(&rule->tos, sizeof(rule->tos), state);
+ siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
+ siphash24_compress(&rule->table, sizeof(rule->table), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
+ const RoutingPolicyRule *a = _a, *b = _b;
+ int r;
+
+ if (a->family < b->family)
+ return -1;
+ if (a->family > b->family)
+ return 1;
+
+ switch (a->family) {
+ case AF_INET:
+ case AF_INET6:
+ if (a->from_prefixlen < b->from_prefixlen)
+ return -1;
+ if (a->from_prefixlen > b->from_prefixlen)
+ return 1;
+
+ if (a->to_prefixlen < b->to_prefixlen)
+ return -1;
+ if (a->to_prefixlen > b->to_prefixlen)
+ return 1;
+
+ if (a->tos < b->tos)
+ return -1;
+ if (a->tos > b->tos)
+ return 1;
+
+ if (a->fwmask < b->fwmark)
+ return -1;
+ if (a->fwmask > b->fwmark)
+ return 1;
+
+ if (a->table < b->table)
+ return -1;
+ if (a->table > b->table)
+ return 1;
+
+ r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
+ if (r != 0)
+ return r;
+
+ return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
+
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+const struct hash_ops routing_policy_rule_hash_ops = {
+ .hash = routing_policy_rule_hash_func,
+ .compare = routing_policy_rule_compare_func
+};
+
+int routing_policy_rule_get(Manager *m,
+ int family,
+ const union in_addr_union *from,
+ uint8_t from_prefixlen,
+ const union in_addr_union *to,
+ uint8_t to_prefixlen,
+ uint8_t tos,
+ uint32_t fwmark,
+ uint32_t table,
+ RoutingPolicyRule **ret) {
+
+ RoutingPolicyRule rule, *existing;
+
+ assert_return(m, -1);
+
+ rule = (RoutingPolicyRule) {
+ .family = family,
+ .from = *from,
+ .from_prefixlen = from_prefixlen,
+ .to = *to,
+ .to_prefixlen = to_prefixlen,
+ .tos = tos,
+ .fwmark = fwmark,
+ .table = table,
+ };
+
+ if (m->rules) {
+ existing = set_get(m->rules, &rule);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 1;
+ }
+ }
+
+ if (m->rules_foreign) {
+ existing = set_get(m->rules_foreign, &rule);
+ if (existing) {
+ if (ret)
+ *ret = existing;
+ return 1;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
+ int r;
+
+ assert(m);
+
+ if (set_contains(m->rules_foreign, rule)) {
+ set_remove(m->rules_foreign, rule);
+
+ r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
+ if (r < 0)
+ return r;
+
+ return set_put(m->rules, rule);
+ }
+
+ return -ENOENT;
+}
+
+static int routing_policy_rule_add_internal(Set **rules,
+ int family,
+ const union in_addr_union *from,
+ uint8_t from_prefixlen,
+ const union in_addr_union *to,
+ uint8_t to_prefixlen,
+ uint8_t tos,
+ uint32_t fwmark,
+ uint32_t table,
+ RoutingPolicyRule **ret) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
+ int r;
+
+ assert_return(rules, -EINVAL);
+
+ r = routing_policy_rule_new(&rule);
+ if (r < 0)
+ return r;
+
+ rule->family = family;
+ rule->from = *from;
+ rule->from_prefixlen = from_prefixlen;
+ rule->to = *to;
+ rule->to_prefixlen = to_prefixlen;
+ rule->tos = tos;
+ rule->fwmark = fwmark;
+ rule->table = table;
+
+ r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(*rules, rule);
+ if (r < 0)
+ return r;
+
+ if (ret)
+ *ret = rule;
+
+ rule = NULL;
+
+ return 0;
+}
+
+int routing_policy_rule_add(Manager *m,
+ int family,
+ const union in_addr_union *from,
+ uint8_t from_prefixlen,
+ const union in_addr_union *to,
+ uint8_t to_prefixlen,
+ uint8_t tos,
+ uint32_t fwmark,
+ uint32_t table,
+ RoutingPolicyRule **ret) {
+
+ return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
+}
+
+int routing_policy_rule_add_foreign(Manager *m,
+ int family,
+ const union in_addr_union *from,
+ uint8_t from_prefixlen,
+ const union in_addr_union *to,
+ uint8_t to_prefixlen,
+ uint8_t tos,
+ uint32_t fwmark,
+ uint32_t table,
+ RoutingPolicyRule **ret) {
+ return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
+}
+
+static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_link_unref_ Link *link = userdata;
+ int r;
+
+ assert(m);
+ assert(link);
+ assert(link->ifname);
+
+ link->link_messages--;
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
+
+ return 1;
+}
+
+int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ assert(routing_policy_rule);
+ assert(link);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+ assert(link->ifindex > 0);
+ assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
+
+ r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
+
+ if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
+ if (routing_policy_rule->family == AF_INET)
+ r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
+ else
+ r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
+
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
+
+ r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set source prefix length: %m");
+ }
+
+ if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
+ if (routing_policy_rule->family == AF_INET)
+ r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
+ else
+ r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
+
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_DST attribute: %m");
+
+ r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set destination prefix length: %m");
+ }
+
+ r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ return 0;
+}
+
+static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
+ _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
+ int r;
+
+ assert(network);
+ assert(ret);
+ assert(!!filename == (section_line > 0));
+
+ r = network_config_section_new(filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ rule = hashmap_get(network->rules_by_section, n);
+ if (rule) {
+ *ret = rule;
+ rule = NULL;
+
+ return 0;
+ }
+
+ r = routing_policy_rule_new(&rule);
+ if (r < 0)
+ return r;
+
+ rule->section = n;
+ rule->network = network;
+ n = NULL;
+
+ r = hashmap_put(network->rules_by_section, rule->section, rule);
+ if (r < 0)
+ return r;
+
+ LIST_APPEND(rules, network->rules, rule);
+ network->n_rules++;
+
+ *ret = rule;
+ rule = NULL;
+
+ return 0;
+}
+
+int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_link_unref_ Link *link = userdata;
+ int r;
+
+ assert(rtnl);
+ assert(m);
+ assert(link);
+ assert(link->ifname);
+ assert(link->link_messages > 0);
+
+ link->link_messages--;
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
+
+ if (link->link_messages == 0)
+ log_link_debug(link, "Routing policy rule configured");
+
+ return 1;
+}
+
+int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ assert(rule);
+ assert(link);
+ assert(link->ifindex > 0);
+ assert(link->manager);
+ assert(link->manager->rtnl);
+
+ r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
+
+ if (!in_addr_is_null(rule->family, &rule->from)) {
+ if (rule->family == AF_INET)
+ r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
+ else
+ r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
+
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
+
+ r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set source prefix length: %m");
+ }
+
+ if (!in_addr_is_null(rule->family, &rule->to)) {
+ if (rule->family == AF_INET)
+ r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
+ else
+ r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
+
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_DST attribute: %m");
+
+ r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set destination prefix length: %m");
+ }
+
+ r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
+
+ if (rule->tos > 0) {
+ r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
+ if (r < 0)
+ return log_error_errno(r, "Could not set ip rule tos: %m");
+ }
+
+ if (rule->table < 256) {
+ r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
+ if (r < 0)
+ return log_error_errno(r, "Could not set ip rule table: %m");
+ } else {
+ r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
+ if (r < 0)
+ return log_error_errno(r, "Could not set ip rule table: %m");
+
+ r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
+ }
+
+ if (rule->fwmark > 0) {
+ r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
+ }
+
+ if (rule->fwmask > 0) {
+ r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
+ if (r < 0)
+ return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
+ }
+
+ rule->link = link;
+
+ r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
+
+ link_ref(link);
+
+ r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
+ rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not add rule : %m");
+
+ return 0;
+}
+
+static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
+ _cleanup_free_ char *f = NULL;
+ char *p;
+ int r;
+
+ assert(s);
+
+ f = strdup(s);
+ if (!f)
+ return -ENOMEM;
+
+ p = strchr(f, '/');
+ if (p)
+ *p++ = '\0';
+
+ r = safe_atou32(f, fwmark);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
+
+ if (p) {
+ r = safe_atou32(p, fwmask);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
+ }
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_tos(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = safe_atou8(rvalue, &n->tos);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_priority(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(rvalue, &n->priority);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_table(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(rvalue, &n->table);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_fwmark_mask(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
+ _cleanup_free_ char *fwmark = NULL;
+ Network *network = userdata;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_routing_policy_rule_prefix(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
+ Network *network = userdata;
+ union in_addr_union buffer;
+ uint8_t prefixlen;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = routing_policy_rule_new_static(network, filename, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
+ if (r < 0) {
+ r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ n->family = AF_INET6;
+ } else
+ n->family = AF_INET;
+
+ if (streq(lvalue, "To")) {
+ n->to = buffer;
+ n->to_prefixlen = prefixlen;
+ } else {
+ n->from = buffer;
+ n->from_prefixlen = prefixlen;
+ }
+
+ n = NULL;
+
+ return 0;
+}
+
+static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
+ _cleanup_free_ char *s = NULL, *p = NULL;
+ size_t size;
+ int r;
+
+ assert(state_file);
+
+ r = read_full_file(state_file, &s, &size);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+ if (size <= 0)
+ return -ENODATA;
+
+ *ret = s;
+ s = NULL;
+
+ return size;
+}
+
+int routing_policy_rule_load(Manager *m) {
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_free_ char *data = NULL;
+ const char *p;
+ char **i;
+ int r;
+
+ assert(m);
+
+ r = routing_policy_rule_read_full_file(m->state_file, &data);
+ if (r <= 0)
+ return r;
+
+ l = strv_split_newlines(data);
+ if (!l)
+ return -ENOMEM;
+
+ r = set_ensure_allocated(&m->rules_saved, &routing_policy_rule_hash_ops);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(i, l) {
+ _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
+
+ p = startswith(*i, "RULE=");
+ if (!p)
+ continue;
+
+ p = strchr(*i, '=');
+ p++;
+
+ r = routing_policy_rule_new(&rule);
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
+ union in_addr_union buffer;
+ uint8_t prefixlen;
+
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = split_pair(word, "=", &a, &b);
+ if (r < 0)
+ continue;
+
+ if (STR_IN_SET(a, "from", "to")) {
+
+ r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
+ if (r < 0) {
+ r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
+ if (r < 0) {
+ log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
+ continue;
+ }
+
+ rule->family = AF_INET6;
+ } else
+ rule->family = AF_INET;
+
+ if (streq(a, "to")) {
+ rule->to = buffer;
+ rule->to_prefixlen = prefixlen;
+ } else {
+ rule->from = buffer;
+ rule->from_prefixlen = prefixlen;
+ }
+ } else if (streq(a, "tos")) {
+ r = safe_atou8(b, &rule->tos);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
+ continue;
+ }
+ } else if (streq(a, "table")) {
+ r = safe_atou32(b, &rule->table);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
+ continue;
+ }
+ } else if (streq(a, "fwmark")) {
+
+ r = parse_fwmark_fwmask(a, &rule->fwmark, &rule->fwmask);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
+ continue;
+ }
+ }
+ }
+
+ r = set_put(m->rules_saved, rule);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
+ continue;
+ }
+
+ rule = NULL;
+ }
+
+ return 0;
+}
+
+void routing_policy_rule_purge(Manager *m, Link *link) {
+ RoutingPolicyRule *rule, *existing;
+ Iterator i;
+ int r;
+
+ assert(m);
+ assert(link);
+
+ SET_FOREACH(rule, m->rules_saved, i) {
+ existing = set_get(m->rules_foreign, rule);
+ if (existing) {
+
+ r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
+ if (r < 0) {
+ log_warning_errno(r, "Could not remove routing policy rules: %m");
+ continue;
+ }
+
+ link->link_messages++;
+ }
+ }
+}
diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h
new file mode 100644
index 0000000000..d9fd93b9bf
--- /dev/null
+++ b/src/network/networkd-routing-policy-rule.h
@@ -0,0 +1,83 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Susant Sahani
+
+ 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 <inttypes.h>
+#include <stdbool.h>
+
+#include "in-addr-util.h"
+
+typedef struct RoutingPolicyRule RoutingPolicyRule;
+
+#include "networkd-link.h"
+#include "networkd-network.h"
+
+typedef struct Network Network;
+typedef struct Link Link;
+typedef struct NetworkConfigSection NetworkConfigSection;
+
+struct RoutingPolicyRule {
+ Network *network;
+ Link *link;
+ NetworkConfigSection *section;
+
+ uint8_t tos;
+
+ uint32_t table;
+ uint32_t fwmark;
+ uint32_t fwmask;
+ uint32_t priority;
+
+ int family;
+ unsigned char to_prefixlen;
+ unsigned char from_prefixlen;
+
+ union in_addr_union to;
+ union in_addr_union from;
+
+ LIST_FIELDS(RoutingPolicyRule, rules);
+};
+
+int routing_policy_rule_new(RoutingPolicyRule **ret);
+void routing_policy_rule_free(RoutingPolicyRule *rule);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(RoutingPolicyRule*, routing_policy_rule_free);
+#define _cleanup_routing_policy_rule_free_ _cleanup_(routing_policy_rule_freep)
+
+int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, sd_netlink_message_handler_t callback, bool update);
+int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback);
+int link_routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+
+int routing_policy_rule_add(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
+ uint8_t tos, uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
+int routing_policy_rule_add_foreign(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen,
+ uint8_t tos, uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
+int routing_policy_rule_get(Manager *m, int family, const union in_addr_union *from, uint8_t from_prefixlen, const union in_addr_union *to, uint8_t to_prefixlen, uint8_t tos,
+ uint32_t fwmark, uint32_t table, RoutingPolicyRule **ret);
+int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule);
+int routing_policy_rule_load(Manager *m);
+void routing_policy_rule_purge(Manager *m, Link *link);
+
+int config_parse_routing_policy_rule_tos(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data,void *userdata);
+int config_parse_routing_policy_rule_table(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_routing_policy_rule_fwmark_mask(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_routing_policy_rule_prefix(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_routing_policy_rule_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data,void *userdata);
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c
index 555a7c68a1..8856e76269 100644
--- a/src/network/networkd-util.c
+++ b/src/network/networkd-util.c
@@ -25,8 +25,7 @@
#include "util.h"
const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
- if (b == ADDRESS_FAMILY_YES ||
- b == ADDRESS_FAMILY_NO)
+ if (IN_SET(b, ADDRESS_FAMILY_YES, ADDRESS_FAMILY_NO))
return yes_no(b == ADDRESS_FAMILY_YES);
if (b == ADDRESS_FAMILY_IPV4)
diff --git a/src/network/networkd.c b/src/network/networkd.c
index fe60f1ed14..d5ba6893e3 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -70,13 +70,17 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
- r = drop_privileges(uid, gid,
- (1ULL << CAP_NET_ADMIN) |
- (1ULL << CAP_NET_BIND_SERVICE) |
- (1ULL << CAP_NET_BROADCAST) |
- (1ULL << CAP_NET_RAW));
- if (r < 0)
- goto out;
+ /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
+ * privileges are already dropped. */
+ if (geteuid() == 0) {
+ r = drop_privileges(uid, gid,
+ (1ULL << CAP_NET_ADMIN) |
+ (1ULL << CAP_NET_BIND_SERVICE) |
+ (1ULL << CAP_NET_BROADCAST) |
+ (1ULL << CAP_NET_RAW));
+ if (r < 0)
+ goto out;
+ }
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
@@ -128,6 +132,12 @@ int main(int argc, char *argv[]) {
goto out;
}
+ r = manager_rtnl_enumerate_rules(m);
+ if (r < 0) {
+ log_error_errno(r, "Could not enumerate rules: %m");
+ goto out;
+ }
+
r = manager_start(m);
if (r < 0) {
log_error_errno(r, "Could not start manager: %m");
diff --git a/src/network/wait-online/Makefile b/src/network/wait-online/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/network/wait-online/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/notify/Makefile b/src/notify/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/notify/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nspawn/.gitignore b/src/nspawn/.gitignore
deleted file mode 100644
index 85c81fff24..0000000000
--- a/src/nspawn/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/nspawn-gperf.c
diff --git a/src/nspawn/Makefile b/src/nspawn/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/nspawn/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf
index e5fdf63162..b61b347ee7 100644
--- a/src/nspawn/nspawn-gperf.gperf
+++ b/src/nspawn/nspawn-gperf.gperf
@@ -29,6 +29,7 @@ Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings,
Exec.PivotRoot, config_parse_pivot_root, 0, 0
Exec.PrivateUsers, config_parse_private_users, 0, 0
Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready)
+Exec.SystemCallFilter, config_parse_syscall_filter,0, 0,
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
Files.Bind, config_parse_bind, 0, 0
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index ac7290732e..531f29cb7b 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -374,7 +374,7 @@ static int tmpfs_patch_options(
options = buf;
}
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (selinux_apifs_context) {
char *t;
@@ -456,9 +456,6 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
if (rmdir(full) < 0)
return log_error_errno(errno, "Failed to remove %s: %m", full);
- x = prefix_roota(top, "/fs/kdbus");
- (void) mkdir_p(x, 0755);
-
/* Create mountpoint for cgroups. Otherwise we are not allowed since we
* remount /sys read-only.
*/
@@ -560,7 +557,7 @@ int mount_all(const char *dest,
{ "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, MOUNT_FATAL },
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, MOUNT_FATAL },
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, MOUNT_FATAL },
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, 0 }, /* Bind mount first */
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, 0 }, /* Then, make it r/o */
#endif
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
index 1a3f129db0..063fdb1053 100644
--- a/src/nspawn/nspawn-patch-uid.c
+++ b/src/nspawn/nspawn-patch-uid.c
@@ -19,7 +19,7 @@
#include <fcntl.h>
#include <linux/magic.h>
-#ifdef HAVE_ACL
+#if HAVE_ACL
#include <sys/acl.h>
#endif
#include <sys/stat.h>
@@ -37,7 +37,7 @@
#include "strv.h"
#include "user-util.h"
-#ifdef HAVE_ACL
+#if HAVE_ACL
static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
@@ -347,6 +347,8 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
}
if (r < 0)
goto finish;
+ if (r > 0)
+ changed = true;
if (S_ISDIR(st->st_mode)) {
_cleanup_closedir_ DIR *d = NULL;
diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c
index 72ecc51b16..1890dd8e27 100644
--- a/src/nspawn/nspawn-seccomp.c
+++ b/src/nspawn/nspawn-seccomp.c
@@ -22,139 +22,205 @@
#include <sys/capability.h>
#include <sys/types.h>
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include <seccomp.h>
#endif
#include "alloc-util.h"
#include "log.h"
#include "nspawn-seccomp.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "string-util.h"
+#include "strv.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
static int seccomp_add_default_syscall_filter(
scmp_filter_ctx ctx,
uint32_t arch,
- uint64_t cap_list_retain) {
+ uint64_t cap_list_retain,
+ char **syscall_whitelist,
+ char **syscall_blacklist) {
static const struct {
uint64_t capability;
- int syscall_num;
- } blacklist[] = {
- { 0, SCMP_SYS(_sysctl) }, /* obsolete syscall */
- { 0, SCMP_SYS(add_key) }, /* keyring is not namespaced */
- { 0, SCMP_SYS(afs_syscall) }, /* obsolete syscall */
- { 0, SCMP_SYS(bdflush) },
-#ifdef __NR_bpf
- { 0, SCMP_SYS(bpf) },
-#endif
- { 0, SCMP_SYS(break) }, /* obsolete syscall */
- { 0, SCMP_SYS(create_module) }, /* obsolete syscall */
- { 0, SCMP_SYS(ftime) }, /* obsolete syscall */
- { 0, SCMP_SYS(get_kernel_syms) }, /* obsolete syscall */
- { 0, SCMP_SYS(getpmsg) }, /* obsolete syscall */
- { 0, SCMP_SYS(gtty) }, /* obsolete syscall */
-#ifdef __NR_kexec_file_load
- { 0, SCMP_SYS(kexec_file_load) },
-#endif
- { 0, SCMP_SYS(kexec_load) },
- { 0, SCMP_SYS(keyctl) }, /* keyring is not namespaced */
- { 0, SCMP_SYS(lock) }, /* obsolete syscall */
- { 0, SCMP_SYS(lookup_dcookie) },
- { 0, SCMP_SYS(mpx) }, /* obsolete syscall */
- { 0, SCMP_SYS(nfsservctl) }, /* obsolete syscall */
- { 0, SCMP_SYS(open_by_handle_at) },
- { 0, SCMP_SYS(perf_event_open) },
- { 0, SCMP_SYS(prof) }, /* obsolete syscall */
- { 0, SCMP_SYS(profil) }, /* obsolete syscall */
- { 0, SCMP_SYS(putpmsg) }, /* obsolete syscall */
- { 0, SCMP_SYS(query_module) }, /* obsolete syscall */
- { 0, SCMP_SYS(quotactl) },
- { 0, SCMP_SYS(request_key) }, /* keyring is not namespaced */
- { 0, SCMP_SYS(security) }, /* obsolete syscall */
- { 0, SCMP_SYS(sgetmask) }, /* obsolete syscall */
- { 0, SCMP_SYS(ssetmask) }, /* obsolete syscall */
- { 0, SCMP_SYS(stty) }, /* obsolete syscall */
- { 0, SCMP_SYS(swapoff) },
- { 0, SCMP_SYS(swapon) },
- { 0, SCMP_SYS(sysfs) }, /* obsolete syscall */
- { 0, SCMP_SYS(tuxcall) }, /* obsolete syscall */
- { 0, SCMP_SYS(ulimit) }, /* obsolete syscall */
- { 0, SCMP_SYS(uselib) }, /* obsolete syscall */
- { 0, SCMP_SYS(ustat) }, /* obsolete syscall */
- { 0, SCMP_SYS(vserver) }, /* obsolete syscall */
- { CAP_SYSLOG, SCMP_SYS(syslog) },
- { CAP_SYS_MODULE, SCMP_SYS(delete_module) },
- { CAP_SYS_MODULE, SCMP_SYS(finit_module) },
- { CAP_SYS_MODULE, SCMP_SYS(init_module) },
- { CAP_SYS_PACCT, SCMP_SYS(acct) },
- { CAP_SYS_PTRACE, SCMP_SYS(process_vm_readv) },
- { CAP_SYS_PTRACE, SCMP_SYS(process_vm_writev) },
- { CAP_SYS_PTRACE, SCMP_SYS(ptrace) },
- { CAP_SYS_RAWIO, SCMP_SYS(ioperm) },
- { CAP_SYS_RAWIO, SCMP_SYS(iopl) },
- { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_iobase) },
- { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_read) },
- { CAP_SYS_RAWIO, SCMP_SYS(pciconfig_write) },
-#ifdef __NR_s390_pci_mmio_read
- { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_read) },
-#endif
-#ifdef __NR_s390_pci_mmio_write
- { CAP_SYS_RAWIO, SCMP_SYS(s390_pci_mmio_write) },
-#endif
- { CAP_SYS_TIME, SCMP_SYS(adjtimex) },
- { CAP_SYS_TIME, SCMP_SYS(clock_adjtime) },
- { CAP_SYS_TIME, SCMP_SYS(clock_settime) },
- { CAP_SYS_TIME, SCMP_SYS(settimeofday) },
- { CAP_SYS_TIME, SCMP_SYS(stime) },
+ const char* name;
+ } whitelist[] = {
+ /* Let's use set names where we can */
+ { 0, "@aio" },
+ { 0, "@basic-io" },
+ { 0, "@chown" },
+ { 0, "@default" },
+ { 0, "@file-system" },
+ { 0, "@io-event" },
+ { 0, "@ipc" },
+ { 0, "@mount" },
+ { 0, "@network-io" },
+ { 0, "@process" },
+ { 0, "@resources" },
+ { 0, "@setuid" },
+ { 0, "@signal" },
+ { 0, "@sync" },
+ { 0, "@timer" },
+
+ /* The following four are sets we optionally enable, in case the caps have been configured for it */
+ { CAP_SYS_TIME, "@clock" },
+ { CAP_SYS_MODULE, "@module" },
+ { CAP_SYS_RAWIO, "@raw-io" },
+ { CAP_IPC_LOCK, "@memlock" },
+
+ /* Plus a good set of additional syscalls which are not part of any of the groups above */
+ { 0, "brk" },
+ { 0, "capget" },
+ { 0, "capset" },
+ { 0, "copy_file_range" },
+ { 0, "fadvise64" },
+ { 0, "fadvise64_64" },
+ { 0, "flock" },
+ { 0, "get_mempolicy" },
+ { 0, "getcpu" },
+ { 0, "getpriority" },
+ { 0, "getrandom" },
+ { 0, "ioctl" },
+ { 0, "ioprio_get" },
+ { 0, "kcmp" },
+ { 0, "madvise" },
+ { 0, "mincore" },
+ { 0, "mprotect" },
+ { 0, "mremap" },
+ { 0, "name_to_handle_at" },
+ { 0, "oldolduname" },
+ { 0, "olduname" },
+ { 0, "personality" },
+ { 0, "readahead" },
+ { 0, "readdir" },
+ { 0, "remap_file_pages" },
+ { 0, "sched_get_priority_max" },
+ { 0, "sched_get_priority_min" },
+ { 0, "sched_getaffinity" },
+ { 0, "sched_getattr" },
+ { 0, "sched_getparam" },
+ { 0, "sched_getscheduler" },
+ { 0, "sched_rr_get_interval" },
+ { 0, "sched_yield" },
+ { 0, "seccomp" },
+ { 0, "sendfile" },
+ { 0, "sendfile64" },
+ { 0, "setdomainname" },
+ { 0, "setfsgid" },
+ { 0, "setfsgid32" },
+ { 0, "setfsuid" },
+ { 0, "setfsuid32" },
+ { 0, "sethostname" },
+ { 0, "setpgid" },
+ { 0, "setsid" },
+ { 0, "splice" },
+ { 0, "sysinfo" },
+ { 0, "tee" },
+ { 0, "umask" },
+ { 0, "uname" },
+ { 0, "userfaultfd" },
+ { 0, "vmsplice" },
+
+ /* The following individual syscalls are added depending on specified caps */
+ { CAP_SYS_PACCT, "acct" },
+ { CAP_SYS_PTRACE, "process_vm_readv" },
+ { CAP_SYS_PTRACE, "process_vm_writev" },
+ { CAP_SYS_PTRACE, "ptrace" },
+ { CAP_SYS_BOOT, "reboot" },
+ { CAP_SYSLOG, "syslog" },
+ { CAP_SYS_TTY_CONFIG, "vhangup" },
+
+ /*
+ * The following syscalls and groups are knowingly excluded:
+ *
+ * @cpu-emulation
+ * @keyring (NB: keyring is not namespaced!)
+ * @obsolete
+ * @swap
+ *
+ * bpf (NB: bpffs is not namespaced!)
+ * fanotify_init
+ * fanotify_mark
+ * kexec_file_load
+ * kexec_load
+ * lookup_dcookie
+ * nfsservctl
+ * open_by_handle_at
+ * perf_event_open
+ * pkey_alloc
+ * pkey_free
+ * pkey_mprotect
+ * quotactl
+ */
};
- unsigned i;
+
int r, c = 0;
+ size_t i;
+ char **p;
- for (i = 0; i < ELEMENTSOF(blacklist); i++) {
- if (blacklist[i].capability != 0 && (cap_list_retain & (1ULL << blacklist[i].capability)))
+ for (i = 0; i < ELEMENTSOF(whitelist); i++) {
+ if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
- r = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EPERM), blacklist[i].syscall_num, 0);
- if (r < 0) {
+ r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist);
+ if (r < 0)
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
- _cleanup_free_ char *n = NULL;
+ log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", whitelist[i].name, seccomp_arch_to_string(arch));
+ else
+ c++;
+ }
- n = seccomp_syscall_resolve_num_arch(arch, blacklist[i].syscall_num);
- log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", strna(n));
- } else
+ STRV_FOREACH(p, syscall_whitelist) {
+ r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist);
+ if (r < 0)
+ log_debug_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m", *p, seccomp_arch_to_string(arch));
+ else
c++;
}
return c;
}
-int setup_seccomp(uint64_t cap_list_retain) {
+int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
uint32_t arch;
int r;
if (!is_seccomp_available()) {
- log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP audit filter");
+ log_debug("SECCOMP features not detected in the kernel, disabling SECCOMP filterering");
return 0;
}
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
- int n;
- log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
+ log_debug("Applying whitelist on architecture: %s", seccomp_arch_to_string(arch));
- r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+ r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(EPERM));
if (r < 0)
return log_error_errno(r, "Failed to allocate seccomp object: %m");
- n = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain);
- if (n < 0)
- return n;
+ r = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain, syscall_whitelist, syscall_blacklist);
+ if (r < 0)
+ return r;
+
+ r = seccomp_load(seccomp);
+ if (IN_SET(r, -EPERM, -EACCES))
+ return log_error_errno(r, "Failed to install seccomp filter: %m");
+ if (r < 0)
+ log_debug_errno(r, "Failed to install filter set for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+ }
+
+ SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+ _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+
+ log_debug("Applying NETLINK_AUDIT mask on architecture: %s", seccomp_arch_to_string(arch));
+
+ r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate seccomp object: %m");
/*
Audit is broken in containers, much of the userspace audit hookup will fail if running inside a
@@ -171,13 +237,10 @@ int setup_seccomp(uint64_t cap_list_retain) {
2,
SCMP_A0(SCMP_CMP_EQ, AF_NETLINK),
SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT));
- if (r < 0)
+ if (r < 0) {
log_debug_errno(r, "Failed to add audit seccomp rule, ignoring: %m");
- else
- n++;
-
- if (n <= 0) /* no rule added? then skip this architecture */
continue;
+ }
r = seccomp_load(seccomp);
if (IN_SET(r, -EPERM, -EACCES))
@@ -191,7 +254,7 @@ int setup_seccomp(uint64_t cap_list_retain) {
#else
-int setup_seccomp(uint64_t cap_list_retain) {
+int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
return 0;
}
diff --git a/src/nspawn/nspawn-seccomp.h b/src/nspawn/nspawn-seccomp.h
index 5bde16faf9..5cf5ad1e14 100644
--- a/src/nspawn/nspawn-seccomp.h
+++ b/src/nspawn/nspawn-seccomp.h
@@ -21,4 +21,4 @@
#include <sys/types.h>
-int setup_seccomp(uint64_t cap_list_retain);
+int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 5217d10665..c02c1ea697 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -93,6 +93,8 @@ Settings* settings_free(Settings *s) {
free(s->pivot_root_new);
free(s->pivot_root_old);
free(s->working_directory);
+ strv_free(s->syscall_whitelist);
+ strv_free(s->syscall_blacklist);
strv_free(s->network_interfaces);
strv_free(s->network_macvlan);
@@ -568,3 +570,51 @@ int config_parse_private_users(
return 0;
}
+
+int config_parse_syscall_filter(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Settings *settings = data;
+ bool negative;
+ const char *items;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ negative = rvalue[0] == '~';
+ items = negative ? rvalue + 1 : rvalue;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&items, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
+ return 0;
+ }
+
+ if (negative)
+ r = strv_extend(&settings->syscall_blacklist, word);
+ else
+ r = strv_extend(&settings->syscall_whitelist, word);
+ if (r < 0)
+ return log_oom();
+ }
+
+ return 0;
+}
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index 021403258f..75d68ce4cf 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -58,7 +58,8 @@ typedef enum SettingsMask {
SETTING_USERNS = 1 << 13,
SETTING_NOTIFY_READY = 1 << 14,
SETTING_PIVOT_ROOT = 1 << 15,
- _SETTINGS_MASK_ALL = (1 << 16) -1
+ SETTING_SYSCALL_FILTER = 1 << 16,
+ _SETTINGS_MASK_ALL = (1 << 17) -1
} SettingsMask;
typedef struct Settings {
@@ -78,6 +79,8 @@ typedef struct Settings {
UserNamespaceMode userns_mode;
uid_t uid_shift, uid_range;
bool notify_ready;
+ char **syscall_whitelist;
+ char **syscall_blacklist;
/* [Image] */
int read_only;
@@ -121,3 +124,4 @@ int config_parse_network_zone(const char *unit, const char *filename, unsigned l
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 8a5fedd4b0..4e3803be82 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
#include <blkid.h>
#endif
#include <errno.h>
@@ -26,7 +26,7 @@
#include <linux/loop.h>
#include <pwd.h>
#include <sched.h>
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include <signal.h>
@@ -208,6 +208,8 @@ static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO;
static void *arg_root_hash = NULL;
static size_t arg_root_hash_size = 0;
+static char **arg_syscall_whitelist = NULL;
+static char **arg_syscall_blacklist = NULL;
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -267,6 +269,8 @@ static void help(void) {
" --capability=CAP In addition to the default, retain specified\n"
" capability\n"
" --drop-capability=CAP Drop the specified capability from the default set\n"
+ " --system-call-filter=LIST|~LIST\n"
+ " Permit/prohibit specific system calls\n"
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
" host, try-guest, try-host\n"
@@ -431,6 +435,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_PRIVATE_USERS_CHOWN,
ARG_NOTIFY_READY,
ARG_ROOT_HASH,
+ ARG_SYSTEM_CALL_FILTER,
};
static const struct option options[] = {
@@ -482,6 +487,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "pivot-root", required_argument, NULL, ARG_PIVOT_ROOT },
{ "notify-ready", required_argument, NULL, ARG_NOTIFY_READY },
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
+ { "system-call-filter", required_argument, NULL, ARG_SYSTEM_CALL_FILTER },
{}
};
@@ -1051,6 +1057,36 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_SYSTEM_CALL_FILTER: {
+ bool negative;
+ const char *items;
+
+ negative = optarg[0] == '~';
+ items = negative ? optarg + 1 : optarg;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&items, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse system call filter: %m");
+
+ if (negative)
+ r = strv_extend(&arg_syscall_blacklist, word);
+ else
+ r = strv_extend(&arg_syscall_whitelist, word);
+ if (r < 0)
+ return log_oom();
+ }
+
+ arg_settings_mask |= SETTING_SYSCALL_FILTER;
+ break;
+ }
+
case '?':
return -EINVAL;
@@ -1198,7 +1234,7 @@ static int verify_arguments(void) {
return -EINVAL;
}
-#ifndef HAVE_LIBIPTC
+#if ! HAVE_LIBIPTC
if (arg_expose_ports) {
log_error("--port= is not supported, compiled without libiptc support.");
return -EOPNOTSUPP;
@@ -1511,7 +1547,7 @@ static int setup_pts(const char *dest) {
const char *p;
int r;
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (arg_selinux_apifs_context)
(void) asprintf(&options,
"newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT ",context=\"%s\"",
@@ -1580,6 +1616,27 @@ static int setup_dev_console(const char *dest, const char *console) {
return mount_verbose(LOG_ERR, console, to, NULL, MS_BIND, NULL);
}
+static int setup_keyring(void) {
+ key_serial_t keyring;
+
+ /* Allocate a new session keyring for the container. This makes sure the keyring of the session systemd-nspawn
+ * was invoked from doesn't leak into the container. Note that by default we block keyctl() and request_key()
+ * anyway via seccomp so doing this operation isn't strictly necessary, but in case people explicitly whitelist
+ * these system calls let's make sure we don't leak anything into the container. */
+
+ keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
+ if (keyring == -1) {
+ if (errno == ENOSYS)
+ log_debug_errno(errno, "Kernel keyring not supported, ignoring.");
+ else if (IN_SET(errno, EACCES, EPERM))
+ log_debug_errno(errno, "Kernel keyring access prohibited, ignoring.");
+ else
+ return log_error_errno(errno, "Setting up kernel keyring failed: %m");
+ }
+
+ return 0;
+}
+
static int setup_kmsg(const char *dest, int kmsg_socket) {
const char *from, *to;
_cleanup_umask_ mode_t u;
@@ -1709,8 +1766,7 @@ static int setup_journal(const char *directory) {
r = readlink_and_make_absolute(p, &d);
if (r >= 0) {
- if ((arg_link_journal == LINK_GUEST ||
- arg_link_journal == LINK_AUTO) &&
+ if (IN_SET(arg_link_journal, LINK_GUEST, LINK_AUTO) &&
path_equal(d, q)) {
r = userns_mkdir(directory, p, 0755, 0, 0);
@@ -2267,14 +2323,16 @@ static int inner_child(
setup_hostname();
if (arg_personality != PERSONALITY_INVALID) {
- if (personality(arg_personality) < 0)
- return log_error_errno(errno, "personality() failed: %m");
+ r = safe_personality(arg_personality);
+ if (r < 0)
+ return log_error_errno(r, "personality() failed: %m");
} else if (secondary) {
- if (personality(PER_LINUX32) < 0)
- return log_error_errno(errno, "personality() failed: %m");
+ r = safe_personality(PER_LINUX32);
+ if (r < 0)
+ return log_error_errno(r, "personality() failed: %m");
}
-#ifdef HAVE_SELINUX
+#if HAVE_SELINUX
if (arg_selinux_context)
if (setexeccon(arg_selinux_context) < 0)
return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
@@ -2604,7 +2662,11 @@ static int outer_child(
if (r < 0)
return r;
- r = setup_seccomp(arg_caps_retain);
+ r = setup_keyring();
+ if (r < 0)
+ return r;
+
+ r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
if (r < 0)
return r;
@@ -2819,7 +2881,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return log_warning_errno(errno, "Couldn't read notification socket: %m");
@@ -2836,7 +2898,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
}
if (!ucred || ucred->pid != inner_child_pid) {
- log_warning("Received notify message without valid credentials. Ignoring.");
+ log_debug("Received notify message without valid credentials. Ignoring.");
return 0;
}
@@ -3109,6 +3171,21 @@ static int load_settings(void) {
if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0)
arg_notify_ready = settings->notify_ready;
+ if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
+
+ if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
+ log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", p);
+ else {
+ strv_free(arg_syscall_whitelist);
+ strv_free(arg_syscall_blacklist);
+
+ arg_syscall_whitelist = settings->syscall_whitelist;
+ arg_syscall_blacklist = settings->syscall_blacklist;
+
+ settings->syscall_whitelist = settings->syscall_blacklist = NULL;
+ }
+ }
+
return 0;
}
diff --git a/src/nss-myhostname/Makefile b/src/nss-myhostname/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/nss-myhostname/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 0570fde592..96ed161ba7 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -86,7 +86,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
return NSS_STATUS_NOTFOUND;
}
- canonical = "gateway";
+ canonical = "_gateway";
} else {
hn = gethostname_malloc();
@@ -211,7 +211,7 @@ static enum nss_status fill_in_hostent(
c++;
l_canonical = strlen(canonical);
- l_additional = additional ? strlen(additional) : 0;
+ l_additional = strlen_ptr(additional);
ms = ALIGN(l_canonical+1)+
(additional ? ALIGN(l_additional+1) : 0) +
sizeof(char*) +
@@ -337,7 +337,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
if (af == AF_UNSPEC)
af = AF_INET;
- if (af != AF_INET && af != AF_INET6) {
+ if (!IN_SET(af, AF_INET, AF_INET6)) {
*errnop = EAFNOSUPPORT;
*h_errnop = NO_DATA;
return NSS_STATUS_UNAVAIL;
@@ -356,7 +356,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
return NSS_STATUS_NOTFOUND;
}
- canonical = "gateway";
+ canonical = "_gateway";
} else {
hn = gethostname_malloc();
@@ -467,7 +467,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
continue;
if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
- canonical = "gateway";
+ canonical = "_gateway";
goto found;
}
}
diff --git a/src/nss-mymachines/Makefile b/src/nss-mymachines/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/nss-mymachines/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index ea90953abb..6e468853a2 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -435,7 +435,7 @@ enum nss_status _nss_mymachines_getpwnam_r(
if (!machine_name_is_valid(machine))
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
/* Make sure we can't deadlock if we are invoked by dbus-daemon. This way, it won't be able to resolve
* these UIDs, but that should be unproblematic as containers should never be able to connect to a bus
* running on the host. */
@@ -519,7 +519,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
if (uid < HOST_UID_LIMIT)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
goto not_found;
r = sd_bus_open_system(&bus);
@@ -613,7 +613,7 @@ enum nss_status _nss_mymachines_getgrnam_r(
if (!machine_name_is_valid(machine))
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
goto not_found;
r = sd_bus_open_system(&bus);
@@ -691,7 +691,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
if (gid < HOST_GID_LIMIT)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
goto not_found;
r = sd_bus_open_system(&bus);
diff --git a/src/nss-resolve/Makefile b/src/nss-resolve/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/nss-resolve/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index ec059d9586..17d125c821 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -307,7 +307,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
if (af == AF_UNSPEC)
af = AF_INET;
- if (af != AF_INET && af != AF_INET6) {
+ if (!IN_SET(af, AF_INET, AF_INET6)) {
r = -EAFNOSUPPORT;
goto fail;
}
diff --git a/src/nss-systemd/Makefile b/src/nss-systemd/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/nss-systemd/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index f404755dac..d856c4c165 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -116,7 +116,7 @@ enum nss_status _nss_systemd_getpwnam_r(
uint32_t translated;
size_t l;
- int r;
+ int bypass, r;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
@@ -129,38 +129,34 @@ enum nss_status _nss_systemd_getpwnam_r(
goto not_found;
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
- if (streq(name, root_passwd.pw_name)) {
- *pwd = root_passwd;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
- }
- if (streq(name, nobody_passwd.pw_name)) {
- *pwd = nobody_passwd;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+ if (streq(name, root_passwd.pw_name)) {
+ *pwd = root_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (streq(name, nobody_passwd.pw_name)) {
+ *pwd = nobody_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
}
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
- if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
-
- /* Access the dynamic UID allocation directly if we are called from dbus-daemon, see above. */
- r = direct_lookup_name(name, (uid_t*) &translated);
- if (r == -ENOENT)
- goto not_found;
- if (r < 0)
- goto fail;
-
- } else {
+ bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
+ if (bypass <= 0) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
r = sd_bus_open_system(&bus);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ bypass = 1;
+ goto direct_lookup;
+ }
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1",
@@ -183,6 +179,16 @@ enum nss_status _nss_systemd_getpwnam_r(
goto fail;
}
+direct_lookup:
+ if (bypass > 0) {
+ /* Access the dynamic UID allocation directly if we are called from dbus-daemon, see above. */
+ r = direct_lookup_name(name, (uid_t*) &translated);
+ if (r == -ENOENT)
+ goto not_found;
+ if (r < 0)
+ goto fail;
+ }
+
l = strlen(name);
if (buflen < l+1) {
*errnop = ERANGE;
@@ -223,7 +229,7 @@ enum nss_status _nss_systemd_getpwuid_r(
_cleanup_free_ char *direct = NULL;
const char *translated;
size_t l;
- int r;
+ int bypass, r;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
@@ -231,37 +237,32 @@ enum nss_status _nss_systemd_getpwuid_r(
goto not_found;
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
- if (uid == root_passwd.pw_uid) {
- *pwd = root_passwd;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
- }
- if (uid == nobody_passwd.pw_uid) {
- *pwd = nobody_passwd;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+ if (uid == root_passwd.pw_uid) {
+ *pwd = root_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (uid == nobody_passwd.pw_uid) {
+ *pwd = nobody_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
}
if (uid <= SYSTEM_UID_MAX)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
-
- r = direct_lookup_uid(uid, &direct);
- if (r == -ENOENT)
- goto not_found;
- if (r < 0)
- goto fail;
-
- translated = direct;
-
- } else {
+ bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
+ if (bypass <= 0) {
r = sd_bus_open_system(&bus);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ bypass = 1;
+ goto direct_lookup;
+ }
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1",
@@ -284,6 +285,18 @@ enum nss_status _nss_systemd_getpwuid_r(
goto fail;
}
+direct_lookup:
+ if (bypass > 0) {
+ r = direct_lookup_uid(uid, &direct);
+ if (r == -ENOENT)
+ goto not_found;
+ if (r < 0)
+ goto fail;
+
+ translated = direct;
+
+ }
+
l = strlen(translated) + 1;
if (buflen < l) {
*errnop = ERANGE;
@@ -320,7 +333,7 @@ enum nss_status _nss_systemd_getgrnam_r(
uint32_t translated;
size_t l;
- int r;
+ int bypass, r;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
@@ -331,37 +344,33 @@ enum nss_status _nss_systemd_getgrnam_r(
goto not_found;
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
- if (streq(name, root_group.gr_name)) {
- *gr = root_group;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
- }
- if (streq(name, nobody_group.gr_name)) {
- *gr = nobody_group;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+ if (streq(name, root_group.gr_name)) {
+ *gr = root_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (streq(name, nobody_group.gr_name)) {
+ *gr = nobody_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
}
- if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
-
- /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
- r = direct_lookup_name(name, (uid_t*) &translated);
- if (r == -ENOENT)
- goto not_found;
- if (r < 0)
- goto fail;
- } else {
-
+ bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
+ if (bypass <= 0) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
r = sd_bus_open_system(&bus);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ bypass = 1;
+ goto direct_lookup;
+ }
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1",
@@ -384,6 +393,16 @@ enum nss_status _nss_systemd_getgrnam_r(
goto fail;
}
+direct_lookup:
+ if (bypass > 0) {
+ /* Access the dynamic GID allocation directly if we are called from dbus-daemon, see above. */
+ r = direct_lookup_name(name, (uid_t*) &translated);
+ if (r == -ENOENT)
+ goto not_found;
+ if (r < 0)
+ goto fail;
+ }
+
l = sizeof(char*) + strlen(name) + 1;
if (buflen < l) {
*errnop = ERANGE;
@@ -422,7 +441,7 @@ enum nss_status _nss_systemd_getgrgid_r(
_cleanup_free_ char *direct = NULL;
const char *translated;
size_t l;
- int r;
+ int bypass, r;
BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
@@ -430,36 +449,32 @@ enum nss_status _nss_systemd_getgrgid_r(
goto not_found;
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
- if (gid == root_group.gr_gid) {
- *gr = root_group;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
- }
- if (gid == nobody_group.gr_gid) {
- *gr = nobody_group;
- *errnop = 0;
- return NSS_STATUS_SUCCESS;
+ if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
+ if (gid == root_group.gr_gid) {
+ *gr = root_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (gid == nobody_group.gr_gid) {
+ *gr = nobody_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
}
if (gid <= SYSTEM_GID_MAX)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
+ if (getenv_bool_secure("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
- if (getenv_bool("SYSTEMD_NSS_BYPASS_BUS") > 0) {
-
- r = direct_lookup_uid(gid, &direct);
- if (r == -ENOENT)
- goto not_found;
- if (r < 0)
- goto fail;
-
- translated = direct;
- } else {
+ bypass = getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS");
+ if (bypass <= 0) {
r = sd_bus_open_system(&bus);
- if (r < 0)
- goto fail;
+ if (r < 0) {
+ bypass = 1;
+ goto direct_lookup;
+ }
r = sd_bus_call_method(bus,
"org.freedesktop.systemd1",
@@ -482,6 +497,18 @@ enum nss_status _nss_systemd_getgrgid_r(
goto fail;
}
+direct_lookup:
+ if (bypass > 0) {
+
+ r = direct_lookup_uid(gid, &direct);
+ if (r == -ENOENT)
+ goto not_found;
+ if (r < 0)
+ goto fail;
+
+ translated = direct;
+ }
+
l = sizeof(char*) + strlen(translated) + 1;
if (buflen < l) {
*errnop = ERANGE;
diff --git a/src/path/Makefile b/src/path/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/path/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/quotacheck/Makefile b/src/quotacheck/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/quotacheck/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c
index a42fce377e..1339564edb 100644
--- a/src/quotacheck/quotacheck.c
+++ b/src/quotacheck/quotacheck.c
@@ -49,7 +49,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
log_warning("Invalid quotacheck.mode= parameter '%s'. Ignoring.", value);
}
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
else if (streq(key, "forcequotacheck") && !value) {
log_warning("Please use 'quotacheck.mode=force' rather than 'forcequotacheck' on the kernel command line.");
arg_force = true;
@@ -61,7 +61,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
static void test_files(void) {
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
if (access("/forcequotacheck", F_OK) >= 0) {
log_error("Please pass 'quotacheck.mode=force' on the kernel command line rather than creating /forcequotacheck on the root file system.");
arg_force = true;
diff --git a/src/random-seed/Makefile b/src/random-seed/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/random-seed/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/rc-local-generator/Makefile b/src/rc-local-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/rc-local-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/remount-fs/Makefile b/src/remount-fs/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/remount-fs/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/reply-password/Makefile b/src/reply-password/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/reply-password/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/resolve/.gitignore b/src/resolve/.gitignore
deleted file mode 100644
index f0835923b7..0000000000
--- a/src/resolve/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/resolved-gperf.c
-/resolved.conf
-/dns_type-from-name.gperf
-/dns_type-from-name.h
-/dns_type-list.txt
-/dns_type-to-name.h
diff --git a/src/resolve/Makefile b/src/resolve/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/resolve/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/resolve/meson.build b/src/resolve/meson.build
index fe228784fa..75e654e60d 100644
--- a/src/resolve/meson.build
+++ b/src/resolve/meson.build
@@ -123,7 +123,7 @@ systemd_resolve_sources = (basic_dns_sources +
systemd_resolve_only_sources +
dns_type_headers)
-if conf.get('ENABLE_RESOLVED', false)
+if conf.get('ENABLE_RESOLVE') == 1
install_data('org.freedesktop.resolve1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.resolve1.service',
@@ -149,7 +149,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dns-packet.c',
basic_dns_sources,
@@ -158,7 +158,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-resolved-packet.c',
basic_dns_sources,
@@ -167,7 +167,7 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dnssec.c',
basic_dns_sources,
@@ -176,12 +176,12 @@ tests += [
[libgcrypt,
libgpg_error,
libm],
- 'ENABLE_RESOLVED'],
+ 'ENABLE_RESOLVE'],
[['src/resolve/test-dnssec-complex.c',
'src/resolve/dns-type.c',
dns_type_headers],
[],
[],
- 'ENABLE_RESOLVED', 'manual'],
+ 'ENABLE_RESOLVE', 'manual'],
]
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index c62058917f..708378573f 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -72,6 +72,7 @@ static enum {
MODE_STATISTICS,
MODE_RESET_STATISTICS,
MODE_FLUSH_CACHES,
+ MODE_RESET_SERVER_FEATURES,
MODE_STATUS,
} arg_mode = MODE_RESOLVE_HOST;
@@ -357,7 +358,7 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
int r;
char ifname[IF_NAMESIZE] = "";
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return log_oom();
@@ -1055,6 +1056,24 @@ static int flush_caches(sd_bus *bus) {
return 0;
}
+static int reset_server_features(sd_bus *bus) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.resolve1",
+ "/org/freedesktop/resolve1",
+ "org.freedesktop.resolve1.Manager",
+ "ResetServerFeatures",
+ &error,
+ NULL,
+ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
char ***l = userdata;
int r;
@@ -1588,6 +1607,8 @@ static void help(void) {
" --reset-statistics Reset resolver statistics\n"
" --status Show link and server status\n"
" --flush-caches Flush all local DNS caches\n"
+ " --reset-server-features\n"
+ " Forget learnt DNS server feature levels\n"
, program_invocation_short_name);
}
@@ -1607,30 +1628,32 @@ static int parse_argv(int argc, char *argv[]) {
ARG_RESET_STATISTICS,
ARG_STATUS,
ARG_FLUSH_CACHES,
+ ARG_RESET_SERVER_FEATURES,
ARG_NO_PAGER,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "type", required_argument, NULL, 't' },
- { "class", required_argument, NULL, 'c' },
- { "legend", required_argument, NULL, ARG_LEGEND },
- { "interface", required_argument, NULL, 'i' },
- { "protocol", required_argument, NULL, 'p' },
- { "cname", required_argument, NULL, ARG_CNAME },
- { "service", no_argument, NULL, ARG_SERVICE },
- { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
- { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
- { "openpgp", no_argument, NULL, ARG_OPENPGP },
- { "tlsa", optional_argument, NULL, ARG_TLSA },
- { "raw", optional_argument, NULL, ARG_RAW },
- { "search", required_argument, NULL, ARG_SEARCH },
- { "statistics", no_argument, NULL, ARG_STATISTICS, },
- { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
- { "status", no_argument, NULL, ARG_STATUS },
- { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "type", required_argument, NULL, 't' },
+ { "class", required_argument, NULL, 'c' },
+ { "legend", required_argument, NULL, ARG_LEGEND },
+ { "interface", required_argument, NULL, 'i' },
+ { "protocol", required_argument, NULL, 'p' },
+ { "cname", required_argument, NULL, ARG_CNAME },
+ { "service", no_argument, NULL, ARG_SERVICE },
+ { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
+ { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
+ { "openpgp", no_argument, NULL, ARG_OPENPGP },
+ { "tlsa", optional_argument, NULL, ARG_TLSA },
+ { "raw", optional_argument, NULL, ARG_RAW },
+ { "search", required_argument, NULL, ARG_SEARCH },
+ { "statistics", no_argument, NULL, ARG_STATISTICS, },
+ { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
+ { "status", no_argument, NULL, ARG_STATUS },
+ { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
+ { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
{}
};
@@ -1814,6 +1837,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_FLUSH_CACHES;
break;
+ case ARG_RESET_SERVER_FEATURES:
+ arg_mode = MODE_RESET_SERVER_FEATURES;
+ break;
+
case ARG_STATUS:
arg_mode = MODE_STATUS;
break;
@@ -1999,6 +2026,16 @@ int main(int argc, char **argv) {
r = flush_caches(bus);
break;
+ case MODE_RESET_SERVER_FEATURES:
+ if (argc > optind) {
+ log_error("Too many arguments.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ r = reset_server_features(bus);
+ break;
+
case MODE_STATUS:
if (argc > optind) {
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 5aa2348576..c6f14eb416 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1569,6 +1569,17 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b
return sd_bus_reply_method_return(message, NULL);
}
+static int bus_method_reset_server_features(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+
+ assert(message);
+ assert(m);
+
+ manager_reset_server_features(m);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
@@ -1587,6 +1598,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0),
+ SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
@@ -1644,8 +1656,7 @@ int manager_connect_bus(Manager *m) {
r = sd_bus_default_system(&m->bus);
if (r < 0) {
/* We failed to connect? Yuck, we must be in early
- * boot. Let's try in 5s again. As soon as we have
- * kdbus we can stop doing this... */
+ * boot. Let's try in 5s again. */
log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 75636e0e56..3cf4261ff0 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -246,7 +246,7 @@ int manager_parse_config_file(Manager *m) {
return r;
}
-#ifndef HAVE_GCRYPT
+#if ! HAVE_GCRYPT
if (m->dnssec_mode != DNSSEC_NO) {
log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
m->dnssec_mode = DNSSEC_NO;
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
index eddab58a81..33bb5a1f95 100644
--- a/src/resolve/resolved-dns-dnssec.c
+++ b/src/resolve/resolved-dns-dnssec.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#include <gcrypt.h>
#endif
@@ -125,7 +125,7 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
return (int) c;
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
static int rr_compare(const void *a, const void *b) {
DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
@@ -1247,10 +1247,10 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
/* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this
* check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */
- if (rr->n_skip_labels_source != 0 && rr->n_skip_labels_source != (unsigned) -1)
+ if (!IN_SET(rr->n_skip_labels_source, 0, (unsigned) -1))
return 0;
/* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */
- if (rr->n_skip_labels_signer != 1 && rr->n_skip_labels_signer != (unsigned) -1)
+ if (!IN_SET(rr->n_skip_labels_signer, 1, (unsigned) -1))
return 0;
if (!nsec3)
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 49a04615d4..e2f227bfc6 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -28,7 +28,6 @@
#define EDNS0_OPT_DO (1<<15)
-#define DNS_PACKET_SIZE_START 512u
assert_cc(DNS_PACKET_SIZE_START > DNS_PACKET_HEADER_SIZE)
typedef struct DnsPacketRewinder {
@@ -44,11 +43,20 @@ static void rewind_dns_packet(DnsPacketRewinder *rewinder) {
#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0)
#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0)
-int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize) {
+int dns_packet_new(
+ DnsPacket **ret,
+ DnsProtocol protocol,
+ size_t min_alloc_dsize,
+ size_t max_size) {
+
DnsPacket *p;
size_t a;
assert(ret);
+ assert(max_size >= DNS_PACKET_HEADER_SIZE);
+
+ if (max_size > DNS_PACKET_SIZE_MAX)
+ max_size = DNS_PACKET_SIZE_MAX;
/* The caller may not check what is going to be truly allocated, so do not allow to
* allocate a DNS packet bigger than DNS_PACKET_SIZE_MAX.
@@ -71,8 +79,8 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize
a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
/* make sure we never allocate more than useful */
- if (a > DNS_PACKET_SIZE_MAX)
- a = DNS_PACKET_SIZE_MAX;
+ if (a > max_size)
+ a = max_size;
p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
if (!p)
@@ -80,6 +88,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc_dsize
p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
p->allocated = a;
+ p->max_size = max_size;
p->protocol = protocol;
p->opt_start = p->opt_size = (size_t) -1;
p->n_ref = 1;
@@ -145,7 +154,7 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc
assert(ret);
- r = dns_packet_new(&p, protocol, min_alloc_dsize);
+ r = dns_packet_new(&p, protocol, min_alloc_dsize, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -314,11 +323,13 @@ static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start
assert(p);
if (p->size + add > p->allocated) {
- size_t a;
+ size_t a, ms;
a = PAGE_ALIGN((p->size + add) * 2);
- if (a > DNS_PACKET_SIZE_MAX)
- a = DNS_PACKET_SIZE_MAX;
+
+ ms = dns_packet_size_max(p);
+ if (a > ms)
+ a = ms;
if (p->size + add > a)
return -EMSGSIZE;
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index a65d6d38cf..b873c0f745 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -56,10 +56,14 @@ struct DnsPacketHeader {
#define UDP_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr))
/* The various DNS protocols deviate in how large a packet can grow,
- but the TCP transport has a 16bit size field, hence that appears to
- be the absolute maximum. */
+ * but the TCP transport has a 16bit size field, hence that appears to
+ * be the absolute maximum. */
#define DNS_PACKET_SIZE_MAX 0xFFFFu
+/* The default size to use for allocation when we don't know how large
+ * the packet will turn out to be. */
+#define DNS_PACKET_SIZE_START 512u
+
/* RFC 1035 say 512 is the maximum, for classic unicast DNS */
#define DNS_PACKET_UNICAST_SIZE_MAX 512u
@@ -69,7 +73,7 @@ struct DnsPacketHeader {
struct DnsPacket {
int n_ref;
DnsProtocol protocol;
- size_t size, allocated, rindex;
+ size_t size, allocated, rindex, max_size;
void *_data; /* don't access directly, use DNS_PACKET_DATA()! */
Hashmap *names; /* For name compression */
size_t opt_start, opt_size;
@@ -183,7 +187,7 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) {
(unsigned) DNS_PACKET_ARCOUNT(p);
}
-int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize);
+int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, size_t max_size);
int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, bool dnssec_checking_disabled);
void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated);
@@ -299,3 +303,13 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family,
return f;
}
}
+
+static inline size_t dns_packet_size_max(DnsPacket *p) {
+ assert(p);
+
+ /* Why not insist on a fully initialized max_size during DnsPacket construction? Well, this way it's easy to
+ * allocate a transient, throw-away DnsPacket on the stack by simple zero initialization, without having to
+ * deal with explicit field initialization. */
+
+ return p->max_size != 0 ? p->max_size : DNS_PACKET_SIZE_MAX;
+}
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 2b091e6c45..c2b29bc452 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -623,7 +623,18 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
q->question_utf8,
q->ifindex,
&answer);
+ if (r == -ENXIO) {
+ /* If we get ENXIO this tells us to generate NXDOMAIN unconditionally. */
+ dns_query_reset_answer(q);
+ q->answer_rcode = DNS_RCODE_NXDOMAIN;
+ q->answer_protocol = dns_synthesize_protocol(q->flags);
+ q->answer_family = dns_synthesize_family(q->flags);
+ q->answer_authenticated = true;
+ *state = DNS_TRANSACTION_RCODE_FAILURE;
+
+ return 0;
+ }
if (r <= 0)
return r;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index ffaefbe3f2..ca54158898 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -632,7 +632,7 @@ int dns_scope_make_reply_packet(
dns_answer_isempty(soa))
return -EINVAL;
- r = dns_packet_new(&p, s->protocol, 0);
+ r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -818,7 +818,7 @@ static int dns_scope_make_conflict_packet(
assert(rr);
assert(ret);
- r = dns_packet_new(&p, s->protocol, 0);
+ r = dns_packet_new(&p, s->protocol, 0, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -904,7 +904,7 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
* messages, not all of them. That should be enough to
* indicate where there might be a conflict */
r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
- if (r == -EEXIST || r == 0)
+ if (IN_SET(r, 0, -EEXIST))
return 0;
if (r < 0)
return log_debug_errno(r, "Failed to queue conflicting RR: %m");
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index b3d37525f4..1b61dea626 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -70,15 +70,12 @@ int dns_server_new(
s->n_ref = 1;
s->manager = m;
- s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;
- s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
- s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
- s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
s->type = type;
s->family = family;
s->address = *in_addr;
s->ifindex = ifindex;
- s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
+
+ dns_server_reset_features(s);
switch (type) {
@@ -828,6 +825,85 @@ void dns_server_flush_cache(DnsServer *s) {
dns_cache_flush(&scope->cache);
}
+void dns_server_reset_features(DnsServer *s) {
+ assert(s);
+
+ s->max_rtt = 0;
+ s->resend_timeout = DNS_TIMEOUT_MIN_USEC;
+
+ s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;
+ s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST;
+
+ s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX;
+
+ s->packet_bad_opt = false;
+ s->packet_rrsig_missing = false;
+
+ s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC;
+
+ s->warned_downgrade = false;
+
+ dns_server_reset_counters(s);
+}
+
+void dns_server_reset_features_all(DnsServer *s) {
+ DnsServer *i;
+
+ LIST_FOREACH(servers, i, s)
+ dns_server_reset_features(i);
+}
+
+void dns_server_dump(DnsServer *s, FILE *f) {
+ assert(s);
+
+ if (!f)
+ f = stdout;
+
+ fputs("[Server ", f);
+ fputs(dns_server_string(s), f);
+ fputs(" type=", f);
+ fputs(dns_server_type_to_string(s->type), f);
+
+ if (s->type == DNS_SERVER_LINK) {
+ assert(s->link);
+
+ fputs(" interface=", f);
+ fputs(s->link->name, f);
+ }
+
+ fputs("]\n", f);
+
+ fputs("\tVerified feature level: ", f);
+ fputs(strna(dns_server_feature_level_to_string(s->verified_feature_level)), f);
+ fputc('\n', f);
+
+ fputs("\tPossible feature level: ", f);
+ fputs(strna(dns_server_feature_level_to_string(s->possible_feature_level)), f);
+ fputc('\n', f);
+
+ fputs("\tDNSSEC Mode: ", f);
+ fputs(strna(dnssec_mode_to_string(dns_server_get_dnssec_mode(s))), f);
+ fputc('\n', f);
+
+ fputs("\tCan do DNSSEC: ", f);
+ fputs(yes_no(dns_server_dnssec_supported(s)), f);
+ fputc('\n', f);
+
+ fprintf(f,
+ "\tMaximum UDP packet size received: %zu\n"
+ "\tFailed UDP attempts: %u\n"
+ "\tFailed TCP attempts: %u\n"
+ "\tSeen truncated packet: %s\n"
+ "\tSeen OPT RR getting lost: %s\n"
+ "\tSeen RRSIG RR missing: %s\n",
+ s->received_udp_packet_max,
+ s->n_failed_udp,
+ s->n_failed_tcp,
+ yes_no(s->packet_truncated),
+ yes_no(s->packet_bad_opt),
+ yes_no(s->packet_rrsig_missing));
+}
+
static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
[DNS_SERVER_SYSTEM] = "system",
[DNS_SERVER_FALLBACK] = "fallback",
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index bc95d53c6a..00edd47d9a 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -151,3 +151,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
extern const struct hash_ops dns_server_hash_ops;
void dns_server_flush_cache(DnsServer *s);
+
+void dns_server_reset_features(DnsServer *s);
+void dns_server_reset_features_all(DnsServer *s);
+
+void dns_server_dump(DnsServer *s, FILE *f);
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 878bae47dc..5892534687 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -221,7 +221,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = writev(fd, iov, 2);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else
s->n_written += ss;
@@ -243,7 +243,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ss = read(fd, (uint8_t*) &s->read_size + s->n_read, sizeof(s->read_size) - s->n_read);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
@@ -260,7 +260,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
ssize_t ss;
if (!s->read_packet) {
- r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size));
+ r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size), DNS_PACKET_SIZE_MAX);
if (r < 0)
return dns_stream_complete(s, -r);
@@ -293,7 +293,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
(uint8_t*) DNS_PACKET_DATA(s->read_packet) + s->n_read - sizeof(s->read_size),
sizeof(s->read_size) + be16toh(s->read_size) - s->n_read);
if (ss < 0) {
- if (errno != EINTR && errno != EAGAIN)
+ if (!IN_SET(errno, EINTR, EAGAIN))
return dns_stream_complete(s, errno);
} else if (ss == 0)
return dns_stream_complete(s, ECONNRESET);
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 7afbfedfb0..5bc79a313e 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -30,9 +30,12 @@ static int manager_dns_stub_tcp_fd(Manager *m);
static int dns_stub_make_reply_packet(
DnsPacket **p,
+ size_t max_size,
DnsQuestion *q,
- DnsAnswer *answer) {
+ DnsAnswer *answer,
+ bool *ret_truncated) {
+ bool truncated = false;
DnsResourceRecord *rr;
unsigned c = 0;
int r;
@@ -43,7 +46,7 @@ static int dns_stub_make_reply_packet(
* roundtrips aren't expensive. */
if (!*p) {
- r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0);
+ r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size);
if (r < 0)
return r;
@@ -71,12 +74,21 @@ static int dns_stub_make_reply_packet(
continue;
add:
r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
+ if (r == -EMSGSIZE) {
+ truncated = true;
+ break;
+ }
if (r < 0)
return r;
c++;
}
+ if (ret_truncated)
+ *ret_truncated = truncated;
+ else if (truncated)
+ return -EMSGSIZE;
+
DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
return 0;
@@ -86,6 +98,7 @@ static int dns_stub_finish_reply_packet(
DnsPacket *p,
uint16_t id,
int rcode,
+ bool tc, /* set the Truncated bit? */
bool add_opt, /* add an OPT RR to this packet? */
bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
bool ad) { /* set the DNSSEC authenticated data bit? */
@@ -110,14 +123,14 @@ static int dns_stub_finish_reply_packet(
DNS_PACKET_HEADER(p)->id = id;
DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
- 1 /* qr */,
- 0 /* opcode */,
- 0 /* aa */,
- 0 /* tc */,
- 1 /* rd */,
- 1 /* ra */,
+ 1 /* qr */,
+ 0 /* opcode */,
+ 0 /* aa */,
+ tc /* tc */,
+ 1 /* rd */,
+ 1 /* ra */,
ad /* ad */,
- 0 /* cd */,
+ 0 /* cd */,
rcode));
if (add_opt) {
@@ -149,12 +162,6 @@ static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *repl
else {
int fd;
- /* Truncate the message to the right size */
- if (reply->size > DNS_PACKET_PAYLOAD_SIZE_MAX(p)) {
- dns_packet_truncate(reply, DNS_PACKET_UNICAST_SIZE_MAX);
- DNS_PACKET_HEADER(reply)->flags = htobe16(be16toh(DNS_PACKET_HEADER(reply)->flags) | DNS_PACKET_FLAG_TC);
- }
-
fd = manager_dns_stub_udp_fd(m);
if (fd < 0)
return log_debug_errno(fd, "Failed to get reply socket: %m");
@@ -178,11 +185,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco
assert(m);
assert(p);
- r = dns_stub_make_reply_packet(&reply, p->question, NULL);
+ r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to make failure packet: %m");
- r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), authenticated);
+ r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, false, !!p->opt, DNS_PACKET_DO(p), authenticated);
if (r < 0)
return log_debug_errno(r, "Failed to build failure packet: %m");
@@ -197,9 +204,10 @@ static void dns_stub_query_complete(DnsQuery *q) {
switch (q->state) {
- case DNS_TRANSACTION_SUCCESS:
+ case DNS_TRANSACTION_SUCCESS: {
+ bool truncated;
- r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer);
+ r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated);
if (r < 0) {
log_debug_errno(r, "Failed to build reply packet: %m");
break;
@@ -221,6 +229,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
q->reply_dns_packet,
DNS_PACKET_ID(q->request_dns_packet),
q->answer_rcode,
+ truncated,
!!q->request_dns_packet->opt,
DNS_PACKET_DO(q->request_dns_packet),
dns_query_fully_authenticated(q));
@@ -231,6 +240,7 @@ static void dns_stub_query_complete(DnsQuery *q) {
(void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
break;
+ }
case DNS_TRANSACTION_RCODE_FAILURE:
(void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q));
@@ -467,7 +477,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
@@ -543,6 +553,14 @@ int manager_dns_stub_start(Manager *m) {
assert(m);
+ if (m->dns_stub_listener_mode == DNS_STUB_LISTENER_NO)
+ log_debug("Not creating stub listener.");
+ else
+ log_debug("Creating stub listener using %s.",
+ m->dns_stub_listener_mode == DNS_STUB_LISTENER_UDP ? "UDP" :
+ m->dns_stub_listener_mode == DNS_STUB_LISTENER_TCP ? "TCP" :
+ "UDP/TCP");
+
if (IN_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_YES, DNS_STUB_LISTENER_UDP))
r = manager_dns_stub_udp_fd(m);
diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c
index e3003411f7..e8592a60d8 100644
--- a/src/resolve/resolved-dns-synthesize.c
+++ b/src/resolve/resolved-dns-synthesize.c
@@ -186,6 +186,7 @@ static int answer_add_addresses_ptr(
unsigned n_addresses,
int af, const union in_addr_union *match) {
+ bool added = false;
unsigned j;
int r;
@@ -215,9 +216,11 @@ static int answer_add_addresses_ptr(
r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
+
+ added = true;
}
- return 0;
+ return added;
}
static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
@@ -240,21 +243,23 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
/* If we have no local addresses then use ::1
* and 127.0.0.2 as local ones. */
- if (af == AF_INET || af == AF_UNSPEC)
+ if (IN_SET(af, AF_INET, AF_UNSPEC))
buffer[n++] = (struct local_address) {
.family = AF_INET,
.ifindex = dns_synthesize_ifindex(ifindex),
.address.in.s_addr = htobe32(0x7F000002),
};
- if (af == AF_INET6 || af == AF_UNSPEC)
+ if (IN_SET(af, AF_INET6, AF_UNSPEC))
buffer[n++] = (struct local_address) {
.family = AF_INET6,
.ifindex = dns_synthesize_ifindex(ifindex),
.address.in6 = in6addr_loopback,
};
- return answer_add_addresses_rr(answer, dns_resource_key_name(key), buffer, n);
+ return answer_add_addresses_rr(answer,
+ dns_resource_key_name(key),
+ buffer, n);
}
}
@@ -263,6 +268,7 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
_cleanup_free_ struct local_address *addresses = NULL;
+ bool added = false;
int n, r;
assert(m);
@@ -271,10 +277,13 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
- /* Always map the IPv4 address 127.0.0.2 to the local
- * hostname, in addition to "localhost": */
+ /* Always map the IPv4 address 127.0.0.2 to the local hostname, in addition to "localhost": */
- r = dns_answer_reserve(answer, 3);
+ r = dns_answer_reserve(answer, 4);
+ if (r < 0)
+ return r;
+
+ r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->full_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
@@ -290,23 +299,37 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add
if (r < 0)
return r;
- return 0;
+ return 1;
}
n = local_addresses(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
+ if (n <= 0)
return n;
+ r = answer_add_addresses_ptr(answer, m->full_hostname, addresses, n, af, address);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ added = true;
+
r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address);
if (r < 0)
return r;
+ if (r > 0)
+ added = true;
+
+ r = answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ added = true;
- return answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address);
+ return added;
}
static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) {
_cleanup_free_ struct local_address *addresses = NULL;
- int n = 0, af;
+ int n = 0, af, r;
assert(m);
assert(key);
@@ -315,11 +338,15 @@ static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifin
af = dns_type_to_af(key->type);
if (af >= 0) {
n = local_gateways(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
- return n;
+ if (n <= 0)
+ return n; /* < 0 means: error; == 0 means we have no gateway */
}
- return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
+ r = answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
+ if (r < 0)
+ return r;
+
+ return 1; /* > 0 means: we have some gateway */
}
static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -331,10 +358,10 @@ static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union
assert(answer);
n = local_gateways(m->rtnl, ifindex, af, &addresses);
- if (n < 0)
+ if (n <= 0)
return n;
- return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
+ return answer_add_addresses_ptr(answer, "_gateway", addresses, n, af, address);
}
int dns_synthesize_answer(
@@ -345,7 +372,7 @@ int dns_synthesize_answer(
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
DnsResourceKey *key;
- bool found = false;
+ bool found = false, nxdomain = false;
int r;
assert(m);
@@ -356,8 +383,7 @@ int dns_synthesize_answer(
const char *name;
int af;
- if (key->class != DNS_CLASS_IN &&
- key->class != DNS_CLASS_ANY)
+ if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
name = dns_resource_key_name(key);
@@ -379,6 +405,10 @@ int dns_synthesize_answer(
r = synthesize_gateway_rr(m, key, ifindex, &answer);
if (r < 0)
return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
+ if (r == 0) { /* if we have no gateway return NXDOMAIN */
+ nxdomain = true;
+ continue;
+ }
} else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
@@ -388,26 +418,35 @@ int dns_synthesize_answer(
return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
} else if (dns_name_address(name, &af, &address) > 0) {
+ int v, w;
- r = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
- if (r < 0)
+ v = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer);
+ if (v < 0)
return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
- r = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
- if (r < 0)
+ w = synthesize_gateway_ptr(m, af, &address, ifindex, &answer);
+ if (w < 0)
return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
+
+ if (v == 0 && w == 0) /* This IP address is neither a local one nor a gateway */
+ continue;
+
} else
continue;
found = true;
}
- r = found;
+ if (found) {
- if (ret) {
- *ret = answer;
- answer = NULL;
- }
+ if (ret) {
+ *ret = answer;
+ answer = NULL;
+ }
+
+ return 1;
+ } else if (nxdomain)
+ return -ENXIO;
- return r;
+ return 0;
}
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 3075f62b5e..3cda429c3c 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -190,7 +190,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
return -EOPNOTSUPP;
/* We only support the IN class */
- if (key->class != DNS_CLASS_IN && key->class != DNS_CLASS_ANY)
+ if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY))
return -EOPNOTSUPP;
if (hashmap_size(s->manager->dns_transactions) >= TRANSACTIONS_MAX)
@@ -1528,8 +1528,7 @@ int dns_transaction_go(DnsTransaction *t) {
af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
- (t->scope->protocol == DNS_PROTOCOL_LLMNR ||
- t->scope->protocol == DNS_PROTOCOL_MDNS)) {
+ IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
usec_t jitter, accuracy;
/* RFC 4795 Section 2.7 suggests all queries should be
@@ -1594,7 +1593,7 @@ int dns_transaction_go(DnsTransaction *t) {
log_debug("Sending query via TCP since it is too large.");
else if (r == -EAGAIN)
log_debug("Sending query via TCP since server doesn't support UDP.");
- if (r == -EMSGSIZE || r == -EAGAIN)
+ if (IN_SET(r, -EMSGSIZE, -EAGAIN))
r = dns_transaction_open_tcp(t);
}
diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c
index dda9875063..e169c8f02f 100644
--- a/src/resolve/resolved-dns-trust-anchor.c
+++ b/src/resolve/resolved-dns-trust-anchor.c
@@ -435,7 +435,7 @@ static int dns_trust_anchor_load_files(
assert(suffix);
assert(loader);
- r = conf_files_list_nulstr(&files, suffix, NULL, trust_anchor_dirs);
+ r = conf_files_list_nulstr(&files, suffix, NULL, 0, trust_anchor_dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate %s trust anchor files: %m", suffix);
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 61a3f20362..3d26831b06 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -111,13 +111,30 @@ Link *link_free(Link *l) {
}
void link_allocate_scopes(Link *l) {
+ bool unicast_relevant;
int r;
assert(l);
- if (link_relevant(l, AF_UNSPEC, false) &&
- l->dns_servers) {
+ /* If a link that used to be relevant is no longer, or a link that did not use to be relevant now becomes
+ * relevant, let's reinit the learnt global DNS server information, since we might talk to different servers
+ * now, even if they have the same addresses as before. */
+
+ unicast_relevant = link_relevant(l, AF_UNSPEC, false);
+ if (unicast_relevant != l->unicast_relevant) {
+ l->unicast_relevant = unicast_relevant;
+
+ dns_server_reset_features_all(l->manager->fallback_dns_servers);
+ dns_server_reset_features_all(l->manager->dns_servers);
+ }
+
+ /* And now, allocate all scopes that makes sense now if we didn't have them yet, and drop those which we don't
+ * need anymore */
+
+ if (unicast_relevant && l->dns_servers) {
if (!l->unicast_scope) {
+ dns_server_reset_features_all(l->dns_servers);
+
r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
if (r < 0)
log_warning_errno(r, "Failed to allocate DNS scope: %m");
@@ -313,8 +330,8 @@ void link_set_dnssec_mode(Link *l, DnssecMode mode) {
assert(l);
-#ifndef HAVE_GCRYPT
- if (mode == DNSSEC_YES || mode == DNSSEC_ALLOW_DOWNGRADE)
+#if ! HAVE_GCRYPT
+ if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE))
log_warning("DNSSEC option for the link cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
return;
#endif
@@ -1050,7 +1067,7 @@ int link_save_user(Link *l) {
if (r < 0)
goto fail;
- fputs("# This is private data. Do not parse.\n", f);
+ fputs_unlocked("# This is private data. Do not parse.\n", f);
v = resolve_support_to_string(l->llmnr_support);
if (v)
@@ -1067,11 +1084,11 @@ int link_save_user(Link *l) {
if (l->dns_servers) {
DnsServer *server;
- fputs("SERVERS=", f);
+ fputs_unlocked("SERVERS=", f);
LIST_FOREACH(servers, server, l->dns_servers) {
if (server != l->dns_servers)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
v = dns_server_string(server);
if (!v) {
@@ -1079,26 +1096,26 @@ int link_save_user(Link *l) {
goto fail;
}
- fputs(v, f);
+ fputs_unlocked(v, f);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
if (l->search_domains) {
DnsSearchDomain *domain;
- fputs("DOMAINS=", f);
+ fputs_unlocked("DOMAINS=", f);
LIST_FOREACH(domains, domain, l->search_domains) {
if (domain != l->search_domains)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
if (domain->route_only)
- fputc('~', f);
+ fputc_unlocked('~', f);
- fputs(DNS_SEARCH_DOMAIN_NAME(domain), f);
+ fputs_unlocked(DNS_SEARCH_DOMAIN_NAME(domain), f);
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
if (!set_isempty(l->dnssec_negative_trust_anchors)) {
@@ -1106,16 +1123,16 @@ int link_save_user(Link *l) {
Iterator i;
char *nta;
- fputs("NTAS=", f);
+ fputs_unlocked("NTAS=", f);
SET_FOREACH(nta, l->dnssec_negative_trust_anchors, i) {
if (space)
- fputc(' ', f);
+ fputc_unlocked(' ', f);
- fputs(nta, f);
+ fputs_unlocked(nta, f);
space = true;
}
- fputc('\n', f);
+ fputc_unlocked('\n', f);
}
r = fflush_and_check(f);
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index 55a56b7906..c20b8b6d29 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -88,6 +88,8 @@ struct Link {
bool loaded;
char *state_file;
+
+ bool unicast_relevant;
};
int link_new(Manager *m, Link **ret, int ifindex);
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index 29396e9973..0cf4583572 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -345,7 +345,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index b6620875ea..23c6731954 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -21,7 +21,7 @@
#include <poll.h>
#include <sys/ioctl.h>
-#ifdef HAVE_LIBIDN2
+#if HAVE_LIBIDN2
#include <idn2.h>
#endif
@@ -328,9 +328,9 @@ static int manager_network_monitor_listen(Manager *m) {
static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
_cleanup_free_ char *h = NULL, *n = NULL;
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
_cleanup_free_ char *utf8 = NULL;
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
int k;
#endif
char label[DNS_LABEL_MAX];
@@ -356,7 +356,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return -EINVAL;
}
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
r = idn2_to_unicode_8z8z(label, &utf8, 0);
if (r != IDN2_OK)
return log_error("Failed to undo IDNA: %s", idn2_strerror(r));
@@ -364,7 +364,7 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
r = strlen(utf8);
decoded = utf8;
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
k = dns_label_undo_idna(label, r, label, sizeof label);
if (k < 0)
return log_error_errno(k, "Failed to undo IDNA: %m");
@@ -519,8 +519,11 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
_cleanup_free_ char *buffer = NULL;
_cleanup_fclose_ FILE *f = NULL;
Manager *m = userdata;
+ DnsServer *server;
size_t size = 0;
DnsScope *scope;
+ Iterator i;
+ Link *l;
assert(s);
assert(si);
@@ -533,6 +536,14 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
LIST_FOREACH(scopes, scope, m->dns_scopes)
dns_scope_dump(scope, f);
+ LIST_FOREACH(servers, server, m->dns_servers)
+ dns_server_dump(server, f);
+ LIST_FOREACH(servers, server, m->fallback_dns_servers)
+ dns_server_dump(server, f);
+ HASHMAP_FOREACH(l, m->links, i)
+ LIST_FOREACH(servers, server, l->dns_servers)
+ dns_server_dump(server, f);
+
if (fflush_and_check(f) < 0)
return log_oom();
@@ -552,6 +563,17 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si
return 0;
}
+static int manager_sigrtmin1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = userdata;
+
+ assert(s);
+ assert(si);
+ assert(m);
+
+ manager_reset_server_features(m);
+ return 0;
+}
+
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -616,6 +638,7 @@ int manager_new(Manager **ret) {
(void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m);
(void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m);
+ (void) sd_event_add_signal(m->event, &m->sigrtmin1_event_source, SIGRTMIN+1, manager_sigrtmin1, m);
manager_cleanup_saved_user(m);
@@ -679,6 +702,7 @@ Manager *manager_free(Manager *m) {
sd_event_source_unref(m->sigusr1_event_source);
sd_event_source_unref(m->sigusr2_event_source);
+ sd_event_source_unref(m->sigrtmin1_event_source);
sd_event_unref(m->event);
@@ -723,7 +747,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (ms < 0)
return ms;
- r = dns_packet_new(&p, protocol, ms);
+ r = dns_packet_new(&p, protocol, ms, DNS_PACKET_SIZE_MAX);
if (r < 0)
return r;
@@ -741,7 +765,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
if (l == 0)
return 0;
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 0;
return -errno;
@@ -1396,6 +1420,19 @@ void manager_flush_caches(Manager *m) {
log_info("Flushed all caches.");
}
+void manager_reset_server_features(Manager *m) {
+ Iterator i;
+ Link *l;
+
+ dns_server_reset_features_all(m->dns_servers);
+ dns_server_reset_features_all(m->fallback_dns_servers);
+
+ HASHMAP_FOREACH(l, m->links, i)
+ dns_server_reset_features_all(l->dns_servers);
+
+ log_info("Resetting learnt feature levels on all servers.");
+}
+
void manager_cleanup_saved_user(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 97c52b7729..32a0e5fe0f 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -126,6 +126,7 @@ struct Manager {
sd_event_source *sigusr1_event_source;
sd_event_source *sigusr2_event_source;
+ sd_event_source *sigrtmin1_event_source;
unsigned n_transactions_total;
unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX];
@@ -184,5 +185,6 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
bool manager_routable(Manager *m, int family);
void manager_flush_caches(Manager *m);
+void manager_reset_server_features(Manager *m);
void manager_cleanup_saved_user(Manager *m);
diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c
index 415dc1a532..6fbf755878 100644
--- a/src/resolve/resolved-mdns.c
+++ b/src/resolve/resolved-mdns.c
@@ -86,27 +86,21 @@ static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) {
key = p->question->keys[0];
r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
- if (r < 0) {
- log_debug_errno(r, "Failed to lookup key: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to lookup key: %m");
if (r == 0)
return 0;
r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &reply);
- if (r < 0) {
- log_debug_errno(r, "Failed to build reply packet: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to build reply packet: %m");
if (!ratelimit_test(&s->ratelimit))
return 0;
r = dns_scope_emit_udp(s, -1, reply);
- if (r < 0) {
- log_debug_errno(r, "Failed to send reply packet: %m");
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to send reply packet: %m");
return 0;
}
diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c
index 3c62550872..e3d6a33409 100644
--- a/src/resolve/resolved-resolv-conf.c
+++ b/src/resolve/resolved-resolv-conf.c
@@ -26,6 +26,7 @@
#include "fileio.h"
#include "ordered-set.h"
#include "resolved-conf.h"
+#include "resolved-dns-server.h"
#include "resolved-resolv-conf.h"
#include "string-util.h"
#include "strv.h"
@@ -87,7 +88,7 @@ int manager_read_resolv_conf(Manager *m) {
char *l;
l = strstrip(line);
- if (*l == '#' || *l == ';')
+ if (IN_SET(*l, '#', ';'))
continue;
a = first_word(l, "nameserver");
@@ -136,6 +137,11 @@ int manager_read_resolv_conf(Manager *m) {
if (m->unicast_scope)
dns_cache_flush(&m->unicast_scope->cache);
+ /* If /etc/resolv.conf changed, make sure to forget everything we learned about the DNS servers. After all we
+ * might now talk to a very different DNS server that just happens to have the same IP address as an old one
+ * (think 192.168.1.1). */
+ dns_server_reset_features_all(m->dns_servers);
+
return 0;
clear:
@@ -165,7 +171,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
}
if (*count == MAXNS)
- fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
+ fputs_unlocked("# Too many DNS servers configured, the following entries may be ignored.\n", f);
(*count)++;
fprintf(f, "nameserver %s\n", dns_server_string(s));
@@ -181,39 +187,39 @@ static void write_resolv_conf_search(
assert(domains);
assert(f);
- fputs("search", f);
+ fputs_unlocked("search", f);
ORDERED_SET_FOREACH(domain, domains, i) {
if (++count > MAXDNSRCH) {
- fputs("\n# Too many search domains configured, remaining ones ignored.", f);
+ fputs_unlocked("\n# Too many search domains configured, remaining ones ignored.", f);
break;
}
length += strlen(domain) + 1;
if (length > 256) {
- fputs("\n# Total length of all search domains is too long, remaining ones ignored.", f);
+ fputs_unlocked("\n# Total length of all search domains is too long, remaining ones ignored.", f);
break;
}
- fputc(' ', f);
- fputs(domain, f);
+ fputc_unlocked(' ', f);
+ fputs_unlocked(domain, f);
}
- fputs("\n", f);
+ fputs_unlocked("\n", f);
}
static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
Iterator i;
- fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
- "# This is a dynamic resolv.conf file for connecting local clients directly to\n"
- "# all known DNS servers.\n#\n"
- "# Third party programs must not access this file directly, but only through the\n"
- "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
- "# replace this symlink by a static file or a different symlink.\n#\n"
- "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
- "# operation for /etc/resolv.conf.\n\n", f);
+ fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n#\n"
+ "# This is a dynamic resolv.conf file for connecting local clients directly to\n"
+ "# all known DNS servers.\n#\n"
+ "# Third party programs must not access this file directly, but only through the\n"
+ "# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
+ "# replace this symlink by a static file or a different symlink.\n#\n"
+ "# See man:systemd-resolved.service(8) for details about the supported modes of\n"
+ "# operation for /etc/resolv.conf.\n\n", f);
if (ordered_set_isempty(dns))
- fputs("# No DNS servers known.\n", f);
+ fputs_unlocked("# No DNS servers known.\n", f);
else {
unsigned count = 0;
DnsServer *s;
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 74603f9311..2eb7bfd030 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -67,15 +67,20 @@ int main(int argc, char *argv[]) {
goto finish;
}
- /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
- r = drop_privileges(uid, gid,
- (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
- (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
- (UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
- if (r < 0)
- goto finish;
+ /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
+ * privileges are already dropped. */
+ if (getuid() == 0) {
+
+ /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
+ r = drop_privileges(uid, gid,
+ (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
+ (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
+ (UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
+ if (r < 0)
+ goto finish;
+ }
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
r = manager_new(&m);
if (r < 0) {
diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c
index 8cbe492526..00dde9b6bd 100644
--- a/src/resolve/test-dns-packet.c
+++ b/src/resolve/test-dns-packet.c
@@ -75,7 +75,7 @@ static void test_packet_from_file(const char* filename, bool canonical) {
assert_se(packet_size > 0);
assert_se(offset + 8 + packet_size <= data_size);
- assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0);
+ assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0);
assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0);
assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0);
@@ -90,7 +90,7 @@ static void test_packet_from_file(const char* filename, bool canonical) {
assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0);
- assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0);
+ assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX) >= 0);
assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0);
assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0);
diff --git a/src/resolve/test-dnssec-complex.c b/src/resolve/test-dnssec-complex.c
index 090b2fac23..25ec6f4352 100644
--- a/src/resolve/test-dnssec-complex.c
+++ b/src/resolve/test-dnssec-complex.c
@@ -218,7 +218,7 @@ int main(int argc, char* argv[]) {
test_hostname_lookup(bus, "poettering.de", AF_INET, NULL);
test_hostname_lookup(bus, "poettering.de", AF_INET6, NULL);
-#if defined(HAVE_LIBIDN2) || defined(HAVE_LIBIDN)
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
/* Unsigned A with IDNA conversion necessary */
test_hostname_lookup(bus, "pöttering.de", AF_UNSPEC, NULL);
test_hostname_lookup(bus, "pöttering.de", AF_INET, NULL);
diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c
index b3018e8239..8cb4b50393 100644
--- a/src/resolve/test-dnssec.c
+++ b/src/resolve/test-dnssec.c
@@ -47,7 +47,7 @@ static void test_dnssec_canonicalize(void) {
test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
}
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
static void test_dnssec_verify_dns_key(void) {
@@ -332,7 +332,7 @@ int main(int argc, char*argv[]) {
test_dnssec_canonicalize();
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
test_dnssec_verify_dns_key();
test_dnssec_verify_rrset();
test_dnssec_verify_rrset2();
diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c
index 1b0041214b..ab11fbcd32 100644
--- a/src/resolve/test-resolved-packet.c
+++ b/src/resolve/test-resolved-packet.c
@@ -27,13 +27,16 @@ static void test_dns_packet_new(void) {
for (i = 0; i <= DNS_PACKET_SIZE_MAX; i++) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i) == 0);
+ assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i, DNS_PACKET_SIZE_MAX) == 0);
log_debug("dns_packet_new: %zu → %zu", i, p->allocated);
assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
+
+ if (i > DNS_PACKET_SIZE_START + 10 && i < DNS_PACKET_SIZE_MAX - 10)
+ i = MIN(i * 2, DNS_PACKET_SIZE_MAX - 10);
}
- assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1) == -EFBIG);
+ assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG);
}
int main(int argc, char **argv) {
diff --git a/src/rfkill/Makefile b/src/rfkill/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/rfkill/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index c0f138b4f4..3aa468f40b 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -35,9 +35,27 @@
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
+#include "list.h"
+/* Note that any write is delayed until exit and the rfkill state will not be
+ * stored for rfkill indices that disappear after a change. */
#define EXIT_USEC (5 * USEC_PER_SEC)
+typedef struct write_queue_item {
+ LIST_FIELDS(struct write_queue_item, queue);
+ int rfkill_idx;
+ char *file;
+ int state;
+} write_queue_item;
+
+static void write_queue_item_free(struct write_queue_item *item)
+{
+ assert(item);
+
+ free(item->file);
+ free(item);
+}
+
static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
[RFKILL_TYPE_ALL] = "all",
[RFKILL_TYPE_WLAN] = "wlan",
@@ -138,17 +156,21 @@ static int wait_for_initialized(
for (;;) {
_cleanup_udev_device_unref_ struct udev_device *t = NULL;
- r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
+ r = fd_wait_for_event(watch_fd, POLLIN, EXIT_USEC);
if (r == -EINTR)
continue;
if (r < 0)
return log_error_errno(r, "Failed to watch udev monitor: %m");
+ if (r == 0) {
+ log_error("Timed out waiting for udev monitor.");
+ return -ETIMEDOUT;
+ }
t = udev_monitor_receive_device(monitor);
if (!t)
continue;
- if (streq_ptr(udev_device_get_sysname(device), sysname)) {
+ if (streq_ptr(udev_device_get_sysname(t), sysname)) {
*ret = udev_device_ref(t);
return 0;
}
@@ -158,18 +180,21 @@ static int wait_for_initialized(
static int determine_state_file(
struct udev *udev,
const struct rfkill_event *event,
- struct udev_device *d,
char **ret) {
+ _cleanup_udev_device_unref_ struct udev_device *d = NULL;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
const char *path_id, *type;
char *state_file;
int r;
assert(event);
- assert(d);
assert(ret);
+ r = find_device(udev, event, &d);
+ if (r < 0)
+ return r;
+
r = wait_for_initialized(udev, d, &device);
if (r < 0)
return r;
@@ -200,7 +225,6 @@ static int load_state(
struct udev *udev,
const struct rfkill_event *event) {
- _cleanup_udev_device_unref_ struct udev_device *device = NULL;
_cleanup_free_ char *state_file = NULL, *value = NULL;
struct rfkill_event we;
ssize_t l;
@@ -213,11 +237,7 @@ static int load_state(
if (shall_restore_state() == 0)
return 0;
- r = find_device(udev, event, &device);
- if (r < 0)
- return r;
-
- r = determine_state_file(udev, event, device, &state_file);
+ r = determine_state_file(udev, event, &state_file);
if (r < 0)
return r;
@@ -257,36 +277,102 @@ static int load_state(
return 0;
}
-static int save_state(
+static void save_state_queue_remove(
+ struct write_queue_item **write_queue,
+ int idx,
+ char *state_file) {
+
+ struct write_queue_item *item, *tmp;
+
+ LIST_FOREACH_SAFE(queue, item, tmp, *write_queue) {
+ if ((state_file && streq(item->file, state_file)) || idx == item->rfkill_idx) {
+ log_debug("Canceled previous save state of '%s' to %s.", one_zero(item->state), item->file);
+ LIST_REMOVE(queue, *write_queue, item);
+ write_queue_item_free(item);
+ }
+ }
+}
+
+static int save_state_queue(
+ struct write_queue_item **write_queue,
int rfkill_fd,
struct udev *udev,
const struct rfkill_event *event) {
- _cleanup_udev_device_unref_ struct udev_device *device = NULL;
_cleanup_free_ char *state_file = NULL;
+ struct write_queue_item *item;
int r;
assert(rfkill_fd >= 0);
assert(udev);
assert(event);
- r = find_device(udev, event, &device);
+ r = determine_state_file(udev, event, &state_file);
if (r < 0)
return r;
+ save_state_queue_remove(write_queue, event->idx, state_file);
- r = determine_state_file(udev, event, device, &state_file);
- if (r < 0)
- return r;
+ item = new0(struct write_queue_item, 1);
+ if (!item)
+ return -ENOMEM;
+
+ item->file = state_file;
+ item->rfkill_idx = event->idx;
+ item->state = event->soft;
+ state_file = NULL;
+
+ LIST_APPEND(queue, *write_queue, item);
- r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ return 0;
+}
+
+static int save_state_cancel(
+ struct write_queue_item **write_queue,
+ int rfkill_fd,
+ struct udev *udev,
+ const struct rfkill_event *event) {
+
+ _cleanup_free_ char *state_file = NULL;
+ int r;
+
+ assert(rfkill_fd >= 0);
+ assert(udev);
+ assert(event);
+
+ r = determine_state_file(udev, event, &state_file);
+ save_state_queue_remove(write_queue, event->idx, state_file);
if (r < 0)
- return log_error_errno(r, "Failed to write state file %s: %m", state_file);
+ return r;
- log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
return 0;
}
+static int save_state_write(struct write_queue_item **write_queue) {
+ struct write_queue_item *item, *tmp;
+ int result = 0;
+ bool error_logged = false;
+ int r;
+
+ LIST_FOREACH_SAFE(queue, item, tmp, *write_queue) {
+ r = write_string_file(item->file, one_zero(item->state), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0) {
+ result = r;
+ if (!error_logged) {
+ log_error_errno(r, "Failed to write state file %s: %m", item->file);
+ error_logged = true;
+ } else
+ log_warning_errno(r, "Failed to write state file %s: %m", item->file);
+ } else
+ log_debug("Saved state '%s' to %s.", one_zero(item->state), item->file);
+
+ LIST_REMOVE(queue, *write_queue, item);
+ write_queue_item_free(item);
+ }
+ return result;
+}
+
int main(int argc, char *argv[]) {
+ LIST_HEAD(write_queue_item, write_queue);
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_close_ int rfkill_fd = -1;
bool ready = false;
@@ -297,6 +383,8 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
+ LIST_HEAD_INIT(write_queue);
+
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
@@ -406,11 +494,12 @@ int main(int argc, char *argv[]) {
case RFKILL_OP_DEL:
log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
+ (void) save_state_cancel(&write_queue, rfkill_fd, udev, &event);
break;
case RFKILL_OP_CHANGE:
log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type);
- (void) save_state(rfkill_fd, udev, &event);
+ (void) save_state_queue(&write_queue, rfkill_fd, udev, &event);
break;
default:
@@ -422,5 +511,7 @@ int main(int argc, char *argv[]) {
r = 0;
finish:
+ (void) save_state_write(&write_queue);
+
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/run/Makefile b/src/run/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/run/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/run/run.c b/src/run/run.c
index 2e6765aa18..f9ca5683a2 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -61,7 +61,12 @@ static int arg_nice = 0;
static bool arg_nice_set = false;
static char **arg_environment = NULL;
static char **arg_property = NULL;
-static bool arg_pty = false;
+static enum {
+ ARG_STDIO_NONE, /* The default, as it is for normal services, stdin connected to /dev/null, and stdout+stderr to the journal */
+ ARG_STDIO_PTY, /* Interactive behaviour, requested by --pty: we allocate a pty and connect it to the TTY we are invoked from */
+ ARG_STDIO_DIRECT, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
+ ARG_STDIO_AUTO, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
+} arg_stdio = ARG_STDIO_NONE;
static usec_t arg_on_active = 0;
static usec_t arg_on_boot = 0;
static usec_t arg_on_startup = 0;
@@ -106,7 +111,9 @@ static void help(void) {
" --gid=GROUP Run as system group\n"
" --nice=NICE Nice level\n"
" -E --setenv=NAME=VALUE Set environment\n"
- " -t --pty Run service on pseudo tty\n"
+ " -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
+ " STDERR\n"
+ " -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
" -q --quiet Suppress information messages during runtime\n\n"
"Timer options:\n"
" --on-active=SECONDS Run after SECONDS delay\n"
@@ -170,8 +177,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "nice", required_argument, NULL, ARG_NICE },
{ "setenv", required_argument, NULL, 'E' },
{ "property", required_argument, NULL, 'p' },
- { "tty", no_argument, NULL, 't' }, /* deprecated */
+ { "tty", no_argument, NULL, 't' }, /* deprecated alias */
{ "pty", no_argument, NULL, 't' },
+ { "pipe", no_argument, NULL, 'P' },
{ "quiet", no_argument, NULL, 'q' },
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
{ "on-boot", required_argument, NULL, ARG_ON_BOOT },
@@ -190,7 +198,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tq", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tPq", options, NULL)) >= 0)
switch (c) {
@@ -279,8 +287,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
- case 't':
- arg_pty = true;
+ case 't': /* --pty */
+ if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
+ arg_stdio = ARG_STDIO_AUTO;
+ else
+ arg_stdio = ARG_STDIO_PTY;
+ break;
+
+ case 'P': /* --pipe */
+ if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
+ arg_stdio = ARG_STDIO_AUTO;
+ else
+ arg_stdio = ARG_STDIO_DIRECT;
break;
case 'q':
@@ -373,6 +391,16 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
+
+ if (arg_stdio == ARG_STDIO_AUTO) {
+ /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
+ * to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
+ * pipeline, but we are neatly interactive with tty-level isolation otherwise. */
+ arg_stdio = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
+ ARG_STDIO_PTY :
+ ARG_STDIO_DIRECT;
+ }
+
if ((optind >= argc) && (!arg_unit || !with_timer())) {
log_error("Command line to execute required.");
return -EINVAL;
@@ -393,18 +421,18 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_pty && (with_timer() || arg_scope)) {
- log_error("--pty is not compatible in timer or --scope mode.");
+ if (arg_stdio != ARG_STDIO_NONE && (with_timer() || arg_scope)) {
+ log_error("--pty/--pipe is not compatible in timer or --scope mode.");
return -EINVAL;
}
- if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) {
- log_error("--pty is only supported when connecting to the local system or containers.");
+ if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE) {
+ log_error("--pty/--pipe is only supported when connecting to the local system or containers.");
return -EINVAL;
}
- if (arg_pty && arg_no_block) {
- log_error("--pty is not compatible with --no-block.");
+ if (arg_stdio != ARG_STDIO_NONE && arg_no_block) {
+ log_error("--pty/--pipe is not compatible with --no-block.");
return -EINVAL;
}
@@ -481,6 +509,7 @@ static int transient_kill_set_properties(sd_bus_message *m) {
}
static int transient_service_set_properties(sd_bus_message *m, char **argv, const char *pty_path) {
+ bool send_term = false;
int r;
assert(m);
@@ -497,7 +526,7 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
if (r < 0)
return r;
- if (arg_wait || arg_pty) {
+ if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
r = sd_bus_message_append(m, "(sv)", "AddRef", "b", 1);
if (r < 0)
return r;
@@ -534,8 +563,6 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
}
if (pty_path) {
- const char *e;
-
r = sd_bus_message_append(m,
"(sv)(sv)(sv)(sv)",
"StandardInput", "s", "tty",
@@ -545,6 +572,23 @@ static int transient_service_set_properties(sd_bus_message *m, char **argv, cons
if (r < 0)
return r;
+ send_term = true;
+
+ } else if (arg_stdio == ARG_STDIO_DIRECT) {
+ r = sd_bus_message_append(m,
+ "(sv)(sv)(sv)",
+ "StandardInputFileDescriptor", "h", STDIN_FILENO,
+ "StandardOutputFileDescriptor", "h", STDOUT_FILENO,
+ "StandardErrorFileDescriptor", "h", STDERR_FILENO);
+ if (r < 0)
+ return r;
+
+ send_term = isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO);
+ }
+
+ if (send_term) {
+ const char *e;
+
e = getenv("TERM");
if (e) {
char *n;
@@ -655,7 +699,7 @@ static int transient_scope_set_properties(sd_bus_message *m) {
if (r < 0)
return r;
- r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
+ r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid_cached());
if (r < 0)
return r;
@@ -772,6 +816,8 @@ typedef struct RunContext {
uint64_t inactive_enter_usec;
char *result;
uint64_t cpu_usage_nsec;
+ uint64_t ip_ingress_bytes;
+ uint64_t ip_egress_bytes;
uint32_t exit_code;
uint32_t exit_status;
} RunContext;
@@ -815,6 +861,8 @@ static int run_context_update(RunContext *c, const char *path) {
{ "ExecMainCode", "i", NULL, offsetof(RunContext, exit_code) },
{ "ExecMainStatus", "i", NULL, offsetof(RunContext, exit_status) },
{ "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
+ { "IPIngressBytes", "t", NULL, offsetof(RunContext, ip_ingress_bytes) },
+ { "IPEgressBytes", "t", NULL, offsetof(RunContext, ip_egress_bytes) },
{}
};
@@ -875,7 +923,7 @@ static int start_transient_service(
assert(argv);
assert(retval);
- if (arg_pty) {
+ if (arg_stdio == ARG_STDIO_PTY) {
if (arg_transport == BUS_TRANSPORT_LOCAL) {
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
@@ -1000,8 +1048,14 @@ static int start_transient_service(
if (!arg_quiet)
log_info("Running as unit: %s", service);
- if (arg_wait || master >= 0) {
- _cleanup_(run_context_free) RunContext c = {};
+ if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
+ _cleanup_(run_context_free) RunContext c = {
+ .cpu_usage_nsec = NSEC_INFINITY,
+ .ip_ingress_bytes = UINT64_MAX,
+ .ip_egress_bytes = UINT64_MAX,
+ .inactive_exit_usec = USEC_INFINITY,
+ .inactive_enter_usec = USEC_INFINITY,
+ };
_cleanup_free_ char *path = NULL;
const char *mt;
@@ -1081,10 +1135,19 @@ static int start_transient_service(
log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
}
- if (c.cpu_usage_nsec > 0 && c.cpu_usage_nsec != NSEC_INFINITY) {
+ if (c.cpu_usage_nsec != NSEC_INFINITY) {
char ts[FORMAT_TIMESPAN_MAX];
log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC));
}
+
+ if (c.ip_ingress_bytes != UINT64_MAX) {
+ char bytes[FORMAT_BYTES_MAX];
+ log_info("IP traffic received: %s", format_bytes(bytes, sizeof(bytes), c.ip_ingress_bytes));
+ }
+ if (c.ip_egress_bytes != UINT64_MAX) {
+ char bytes[FORMAT_BYTES_MAX];
+ log_info("IP traffic sent: %s", format_bytes(bytes, sizeof(bytes), c.ip_egress_bytes));
+ }
}
/* Try to propagate the service's return value */
@@ -1440,7 +1503,7 @@ int main(int argc, char* argv[]) {
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
* connection */
- if (arg_wait || arg_pty)
+ if (arg_wait || arg_stdio != ARG_STDIO_NONE)
r = bus_connect_transport(arg_transport, arg_host, arg_user, &bus);
else
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
diff --git a/src/shared/Makefile b/src/shared/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/shared/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h
index 396e9e067e..a0e31d8e29 100644
--- a/src/shared/acl-util.h
+++ b/src/shared/acl-util.h
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_ACL
+#if HAVE_ACL
#include <acl/libacl.h>
#include <stdbool.h>
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index e3b29e390c..e33d8b11cf 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -49,6 +49,7 @@
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
+#include "process-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "socket-util.h"
@@ -319,7 +320,7 @@ int ask_password_tty(
n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1);
if (n < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
@@ -336,7 +337,7 @@ int ask_password_tty(
backspace_chars(ttyfd, p);
p = 0;
- } else if (c == '\b' || c == 127) {
+ } else if (IN_SET(c, '\b', 127)) {
if (p > 0) {
@@ -519,7 +520,7 @@ int ask_password_agent(
"AcceptCached=%i\n"
"Echo=%i\n"
"NotAfter="USEC_FMT"\n",
- getpid(),
+ getpid_cached(),
socket_name,
(flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
(flags & ASK_PASSWORD_ECHO) ? 1 : 0,
@@ -612,8 +613,7 @@ int ask_password_agent(
n = recvmsg(socket_fd, &msghdr, 0);
if (n < 0) {
- if (errno == EAGAIN ||
- errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
continue;
r = -errno;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 5cbe663fa8..e191f8c93e 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -21,10 +21,15 @@
#include "bus-internal.h"
#include "bus-unit-util.h"
#include "bus-util.h"
+#include "cap-list.h"
#include "cgroup-util.h"
+#include "cpu-set-util.h"
#include "env-util.h"
+#include "errno-list.h"
#include "escape.h"
#include "hashmap.h"
+#include "hostname-util.h"
+#include "in-addr-util.h"
#include "list.h"
#include "locale-util.h"
#include "mount-util.h"
@@ -33,10 +38,12 @@
#include "path-util.h"
#include "process-util.h"
#include "rlimit-util.h"
+#include "securebits-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "syslog-util.h"
#include "terminal-util.h"
+#include "user-util.h"
#include "utf8.h"
#include "util.h"
@@ -61,6 +68,31 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
&u->job_path);
}
+static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
+ int r;
+
+ assert(m);
+ assert(prefix);
+
+ r = sd_bus_message_open_container(m, 'r', "iayu");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "i", family);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "u", prefixlen);
+ if (r < 0)
+ return r;
+
+ return sd_bus_message_close_container(m);
+}
+
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
const char *eq, *field;
UnitDependency dep;
@@ -202,13 +234,14 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
} else if (STR_IN_SET(field,
- "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting",
- "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "NoNewPrivileges",
- "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute",
- "RestrictRealtime", "DynamicUser", "RemoveIPC", "ProtectKernelTunables",
- "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS")) {
+ "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting",
+ "TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem",
+ "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
+ "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
+ "NoNewPrivileges", "SyslogLevelPrefix", "Delegate", "RemainAfterElapse",
+ "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
+ "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
+ "CPUSchedulingResetOnFork", "LockPersonality")) {
r = parse_boolean(eq);
if (r < 0)
@@ -267,10 +300,25 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"Description", "Slice", "Type", "WorkingDirectory",
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
"ProtectHome", "SELinuxContext", "Restart", "RootImage",
- "NotifyAccess"))
+ "NotifyAccess", "RuntimeDirectoryPreserve", "Personality",
+ "KeyringMode"))
r = sd_bus_message_append(m, "v", "s", eq);
- else if (streq(field, "SyslogLevel")) {
+ else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
+ bool ignore;
+ const char *s;
+
+ if (eq[0] == '-') {
+ ignore = true;
+ s = eq + 1;
+ } else {
+ ignore = false;
+ s = eq;
+ }
+
+ r = sd_bus_message_append(m, "v", "(bs)", ignore, s);
+
+ } else if (streq(field, "SyslogLevel")) {
int level;
level = log_level_from_string(eq);
@@ -292,6 +340,37 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", facility);
+ } else if (streq(field, "SecureBits")) {
+
+ r = secure_bits_from_string(eq);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", r);
+
+ } else if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
+ uint64_t sum = 0;
+ bool invert = false;
+ const char *p;
+
+ p = eq;
+ if (*p == '~') {
+ invert = true;
+ p++;
+ }
+
+ r = capability_set_from_string(p, &sum);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ sum = invert ? ~sum : sum;
+
+ r = sd_bus_message_append(m, "v", "t", sum);
+
} else if (streq(field, "DeviceAllow")) {
if (isempty(eq))
@@ -381,6 +460,135 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "a(st)", 1, path, u);
}
+ } else if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) {
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "v", "a(iayu)", 0);
+ else {
+ unsigned char prefixlen;
+ union in_addr_union prefix = {};
+ int family;
+
+ r = sd_bus_message_open_container(m, 'v', "a(iayu)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(iayu)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (streq(eq, "any")) {
+ /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
+
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else if (is_localhost(eq)) {
+ /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
+
+ prefix.in.s_addr = htobe32(0x7f000000);
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
+ if (r < 0)
+ return r;
+
+ } else if (streq(eq, "link-local")) {
+
+ /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
+
+ prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) {
+ .__in6_u.__u6_addr32[0] = htobe32(0xfe800000)
+ };
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else if (streq(eq, "multicast")) {
+
+ /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
+
+ prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
+ r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ prefix.in6 = (struct in6_addr) {
+ .__in6_u.__u6_addr32[0] = htobe32(0xff000000)
+ };
+ r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ } else {
+ r = in_addr_prefix_from_string_auto(eq, &family, &prefix, &prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse IP address prefix: %s", eq);
+
+ r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ } else if (streq(field, "CPUSchedulingPolicy")) {
+ int n;
+
+ n = sched_policy_from_string(eq);
+ if (n < 0)
+ return log_error_errno(r, "Failed to parse CPUSchedulingPolicy: %s", eq);
+
+ r = sd_bus_message_append(m, "v", "i", (int32_t) n);
+
+ } else if (streq(field, "CPUSchedulingPriority")) {
+ int n;
+
+ r = safe_atoi(eq, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse CPUSchedulingPriority: %s", eq);
+ if (!sched_priority_is_valid(n))
+ return log_error_errno(r, "Invalid CPUSchedulingPriority: %s", eq);
+
+ r = sd_bus_message_append(m, "v", "i", (int32_t) n);
+
+ } else if (streq(field, "CPUAffinity")) {
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ int ncpus;
+
+ ncpus = parse_cpu_set(eq, &cpuset);
+ if (ncpus < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = sd_bus_message_open_container(m, 'v', "ay");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (cpuset)
+ sd_bus_message_append_array(m, 'y', cpuset, CPU_ALLOC_SIZE(ncpus));
+
+ r = sd_bus_message_close_container(m);
+
} else if (streq(field, "Nice")) {
int n;
@@ -390,6 +598,142 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", (int32_t) n);
+#if HAVE_SECCOMP
+
+ } else if (streq(field, "SystemCallFilter")) {
+ int whitelist;
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "bas");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+ if (*p == '~') {
+ whitelist = 0;
+ p++;
+ } else
+ whitelist = 1;
+
+ r = sd_bus_message_append_basic(m, 'b', &whitelist);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (whitelist != 0) {
+ r = sd_bus_message_append_basic(m, 's', "@default");
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (streq(field, "SystemCallArchitectures")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (p = eq;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (streq(field, "SystemCallErrorNumber")) {
+ int n;
+
+ n = errno_from_name(eq);
+ if (n < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+
+ r = sd_bus_message_append(m, "v", "i", (int32_t) n);
+
+ } else if (streq(field, "RestrictAddressFamilies")) {
+ int whitelist;
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "bas");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+ if (*p == '~') {
+ whitelist = 0;
+ p++;
+ } else
+ whitelist = 1;
+
+ r = sd_bus_message_append_basic(m, 'b', &whitelist);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+#endif
+
} else if (streq(field, "FileDescriptorStoreMax")) {
unsigned u;
@@ -417,7 +761,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", (int32_t) q);
- } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
+ } else if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment")) {
const char *p;
r = sd_bus_message_open_container(m, 'v', "as");
@@ -444,6 +788,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
log_error("Invalid environment assignment: %s", word);
return -EINVAL;
}
+ } else if (streq(field, "UnsetEnvironment")) {
+ if (!env_assignment_is_valid(word) && !env_name_is_valid(word)) {
+ log_error("Invalid environment name or assignment: %s", word);
+ return -EINVAL;
+ }
} else { /* PassEnvironment */
if (!env_name_is_valid(word)) {
log_error("Invalid environment variable name: %s", word);
@@ -548,7 +897,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_close_container(m);
- } else if (streq(field, "RuntimeDirectory")) {
+ } else if (streq(field, "SupplementaryGroups")) {
const char *p;
r = sd_bus_message_open_container(m, 'v', "as");
@@ -563,9 +912,57 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+ if (r == 0)
+ break;
+
+ if (!valid_user_group_name_or_id(word)) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append_basic(m, 's', word);
if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (STR_IN_SET(field, "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode", "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask")) {
+ mode_t mode;
+
+ r = parse_mode(eq, &mode);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+
+ r = sd_bus_message_append(m, "v", "u", mode);
+
+ } else if (STR_IN_SET(field, "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (p = eq;;) {
+ _cleanup_free_ char *word = NULL;
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s", field, eq);
if (r == 0)
break;
@@ -856,6 +1253,9 @@ static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
assert(d->name);
assert(result);
+ if (!endswith(d->name, ".service"))
+ return -EINVAL;
+
dbus_path = unit_dbus_path_from_name(d->name);
if (!dbus_path)
return -ENOMEM;
@@ -953,14 +1353,14 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const*
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
else if (streq(d->result, "collected"))
log_error("Queued job for %s was garbage collected.", strna(d->name));
- else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
+ else if (!STR_IN_SET(d->result, "done", "skipped")) {
if (d->name) {
- int q;
_cleanup_free_ char *result = NULL;
+ int q;
q = bus_job_get_service_result(d, &result);
if (q < 0)
- log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
+ log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
log_job_error_with_service_result(d->name, result, extra_args);
} else
@@ -980,7 +1380,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const*
r = -EPROTO;
else if (streq(d->result, "unsupported"))
r = -EOPNOTSUPP;
- else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
+ else if (!STR_IN_SET(d->result, "done", "skipped"))
r = -EIO;
return r;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 91b7fc3a39..1bee740c99 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -39,10 +39,13 @@
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
+#include "cap-list.h"
+#include "cgroup-util.h"
#include "def.h"
#include "escape.h"
#include "fd-util.h"
#include "missing.h"
+#include "mount-util.h"
#include "nsflags.h"
#include "parse-util.h"
#include "proc-cmdline.h"
@@ -252,7 +255,7 @@ int bus_test_polkit(
return r;
else if (r > 0)
return 1;
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -331,7 +334,7 @@ int bus_test_polkit(
return -EACCES;
}
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
typedef struct AsyncPolkitQuery {
sd_bus_message *request, *reply;
@@ -395,7 +398,7 @@ int bus_verify_polkit_async(
Hashmap **registry,
sd_bus_error *error) {
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
_cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL;
AsyncPolkitQuery *q;
const char *sender, **k, **v;
@@ -413,7 +416,7 @@ int bus_verify_polkit_async(
if (r != 0)
return r;
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
q = hashmap_get(*registry, call);
if (q) {
int authorized, challenge;
@@ -460,7 +463,7 @@ int bus_verify_polkit_async(
else if (r > 0)
return 1;
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
if (sd_bus_get_current_message(call->bus) != call)
return -EINVAL;
@@ -549,7 +552,7 @@ int bus_verify_polkit_async(
}
void bus_verify_polkit_async_registry_free(Hashmap *registry) {
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
AsyncPolkitQuery *q;
while ((q = hashmap_steal_first(registry)))
@@ -592,28 +595,8 @@ int bus_connect_system_systemd(sd_bus **_bus) {
if (geteuid() != 0)
return sd_bus_default_system(_bus);
- /* If we are root and kdbus is not available, then let's talk
- * directly to the system instance, instead of going via the
- * bus */
-
- r = sd_bus_new(&bus);
- if (r < 0)
- return r;
-
- r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
- if (r < 0)
- return r;
-
- bus->bus_client = true;
-
- r = sd_bus_start(bus);
- if (r >= 0) {
- *_bus = bus;
- bus = NULL;
- return 0;
- }
-
- bus = sd_bus_unref(bus);
+ /* If we are root then let's talk directly to the system
+ * instance, instead of going via the bus */
r = sd_bus_new(&bus);
if (r < 0)
@@ -643,28 +626,8 @@ int bus_connect_user_systemd(sd_bus **_bus) {
const char *e;
int r;
- /* Try via kdbus first, and then directly */
-
assert(_bus);
- r = sd_bus_new(&bus);
- if (r < 0)
- return r;
-
- if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
- return -ENOMEM;
-
- bus->bus_client = true;
-
- r = sd_bus_start(bus);
- if (r >= 0) {
- *_bus = bus;
- bus = NULL;
- return 0;
- }
-
- bus = sd_bus_unref(bus);
-
e = secure_getenv("XDG_RUNTIME_DIR");
if (!e)
return sd_bus_default_user(_bus);
@@ -771,7 +734,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
} else if (streq(name, "RestrictNamespaces")) {
_cleanup_free_ char *s = NULL;
- const char *result = NULL;
+ const char *result;
if ((u & NAMESPACE_FLAGS_ALL) == 0)
result = "yes";
@@ -786,7 +749,40 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
}
print_property(name, "%s", result);
- } else
+
+ } else if (streq(name, "MountFlags")) {
+ const char *result;
+
+ result = mount_propagation_flags_to_string(u);
+ if (!result)
+ return -EINVAL;
+
+ print_property(name, "%s", result);
+
+ } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
+ _cleanup_free_ char *s = NULL;
+
+ r = capability_set_to_string_alloc(u, &s);
+ if (r < 0)
+ return r;
+
+ print_property(name, "%s", s);
+
+ } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
+ (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
+ (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
+ (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
+ (endswith(name, "NSec") && u == (uint64_t) -1))
+
+ print_property(name, "%s", "[not set]");
+
+ else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
+ (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
+ (startswith(name, "Limit") && u == (uint64_t) -1) ||
+ (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
+
+ print_property(name, "%s", "infinity");
+ else
print_property(name, "%"PRIu64, u);
return 1;
@@ -813,7 +809,17 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
if (strstr(name, "UMask") || strstr(name, "Mode"))
print_property(name, "%04o", u);
- else
+ else if (streq(name, "UID")) {
+ if (u == UID_INVALID)
+ print_property(name, "%s", "[not set]");
+ else
+ print_property(name, "%"PRIu32, u);
+ } else if (streq(name, "GID")) {
+ if (u == GID_INVALID)
+ print_property(name, "%s", "[not set]");
+ else
+ print_property(name, "%"PRIu32, u);
+ } else
print_property(name, "%"PRIu32, u);
return 1;
@@ -856,7 +862,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
if (first && !value)
printf("%s=", name);
- /* This property has multiple space-seperated values, so
+ /* This property has multiple space-separated values, so
* neither spaces not newlines can be allowed in a value. */
good = str[strcspn(str, " \n")] == '\0';
@@ -1541,7 +1547,7 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
}
bool is_kdbus_wanted(void) {
-#ifdef ENABLE_KDBUS
+#if ENABLE_KDBUS
static int wanted = -1;
if (wanted < 0) {
@@ -1563,7 +1569,7 @@ finish:
}
bool is_kdbus_available(void) {
-#ifdef ENABLE_KDBUS
+#if ENABLE_KDBUS
static int available = -1;
if (!is_kdbus_wanted())
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index f59f6f23ae..64f81bb5d3 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -54,7 +54,7 @@ static bool match_uid_gid(uid_t subject_uid, gid_t subject_gid, uid_t delete_uid
return false;
}
-static int clean_sysvipc_shm(uid_t delete_uid, gid_t delete_gid) {
+static int clean_sysvipc_shm(uid_t delete_uid, gid_t delete_gid, bool rm) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
bool first = true;
@@ -92,17 +92,23 @@ static int clean_sysvipc_shm(uid_t delete_uid, gid_t delete_gid) {
if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
continue;
+ if (!rm)
+ return 1;
+
if (shmctl(shmid, IPC_RMID, NULL) < 0) {
/* Ignore entries that are already deleted */
- if (errno == EIDRM || errno == EINVAL)
+ if (IN_SET(errno, EIDRM, EINVAL))
continue;
ret = log_warning_errno(errno,
"Failed to remove SysV shared memory segment %i: %m",
shmid);
- } else
+ } else {
log_debug("Removed SysV shared memory segment %i.", shmid);
+ if (ret == 0)
+ ret = 1;
+ }
}
return ret;
@@ -111,7 +117,7 @@ fail:
return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
}
-static int clean_sysvipc_sem(uid_t delete_uid, gid_t delete_gid) {
+static int clean_sysvipc_sem(uid_t delete_uid, gid_t delete_gid, bool rm) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
bool first = true;
@@ -144,17 +150,23 @@ static int clean_sysvipc_sem(uid_t delete_uid, gid_t delete_gid) {
if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
continue;
+ if (!rm)
+ return 1;
+
if (semctl(semid, 0, IPC_RMID) < 0) {
/* Ignore entries that are already deleted */
- if (errno == EIDRM || errno == EINVAL)
+ if (IN_SET(errno, EIDRM, EINVAL))
continue;
ret = log_warning_errno(errno,
"Failed to remove SysV semaphores object %i: %m",
semid);
- } else
+ } else {
log_debug("Removed SysV semaphore %i.", semid);
+ if (ret == 0)
+ ret = 1;
+ }
}
return ret;
@@ -163,7 +175,7 @@ fail:
return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
}
-static int clean_sysvipc_msg(uid_t delete_uid, gid_t delete_gid) {
+static int clean_sysvipc_msg(uid_t delete_uid, gid_t delete_gid, bool rm) {
_cleanup_fclose_ FILE *f = NULL;
char line[LINE_MAX];
bool first = true;
@@ -197,17 +209,23 @@ static int clean_sysvipc_msg(uid_t delete_uid, gid_t delete_gid) {
if (!match_uid_gid(uid, gid, delete_uid, delete_gid))
continue;
+ if (!rm)
+ return 1;
+
if (msgctl(msgid, IPC_RMID, NULL) < 0) {
/* Ignore entries that are already deleted */
- if (errno == EIDRM || errno == EINVAL)
+ if (IN_SET(errno, EIDRM, EINVAL))
continue;
ret = log_warning_errno(errno,
"Failed to remove SysV message queue %i: %m",
msgid);
- } else
+ } else {
log_debug("Removed SysV message queue %i.", msgid);
+ if (ret == 0)
+ ret = 1;
+ }
}
return ret;
@@ -216,7 +234,7 @@ fail:
return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
}
-static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid) {
+static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid, bool rm) {
struct dirent *de;
int ret = 0, r;
@@ -236,9 +254,6 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid) {
continue;
}
- if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
- continue;
-
if (S_ISDIR(st.st_mode)) {
_cleanup_closedir_ DIR *kid;
@@ -247,29 +262,47 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid) {
if (errno != ENOENT)
ret = log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
} else {
- r = clean_posix_shm_internal(kid, uid, gid);
+ r = clean_posix_shm_internal(kid, uid, gid, rm);
if (r < 0)
ret = r;
}
+ if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
+ continue;
+
+ if (!rm)
+ return 1;
+
if (unlinkat(dirfd(dir), de->d_name, AT_REMOVEDIR) < 0) {
if (errno == ENOENT)
continue;
ret = log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
- } else
+ } else {
log_debug("Removed POSIX shared memory directory %s", de->d_name);
+ if (ret == 0)
+ ret = 1;
+ }
} else {
+ if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
+ continue;
+
+ if (!rm)
+ return 1;
+
if (unlinkat(dirfd(dir), de->d_name, 0) < 0) {
if (errno == ENOENT)
continue;
ret = log_warning_errno(errno, "Failed to remove POSIX shared memory segment %s: %m", de->d_name);
- } else
+ } else {
log_debug("Removed POSIX shared memory segment %s", de->d_name);
+ if (ret == 0)
+ ret = 1;
+ }
}
}
@@ -279,7 +312,7 @@ fail:
return log_warning_errno(errno, "Failed to read /dev/shm: %m");
}
-static int clean_posix_shm(uid_t uid, gid_t gid) {
+static int clean_posix_shm(uid_t uid, gid_t gid, bool rm) {
_cleanup_closedir_ DIR *dir = NULL;
dir = opendir("/dev/shm");
@@ -290,10 +323,10 @@ static int clean_posix_shm(uid_t uid, gid_t gid) {
return log_warning_errno(errno, "Failed to open /dev/shm: %m");
}
- return clean_posix_shm_internal(dir, uid, gid);
+ return clean_posix_shm_internal(dir, uid, gid, rm);
}
-static int clean_posix_mq(uid_t uid, gid_t gid) {
+static int clean_posix_mq(uid_t uid, gid_t gid, bool rm) {
_cleanup_closedir_ DIR *dir = NULL;
struct dirent *de;
int ret = 0;
@@ -326,6 +359,9 @@ static int clean_posix_mq(uid_t uid, gid_t gid) {
if (!match_uid_gid(st.st_uid, st.st_gid, uid, gid))
continue;
+ if (!rm)
+ return 1;
+
fn[0] = '/';
strcpy(fn+1, de->d_name);
@@ -336,8 +372,11 @@ static int clean_posix_mq(uid_t uid, gid_t gid) {
ret = log_warning_errno(errno,
"Failed to unlink POSIX message queue %s: %m",
fn);
- } else
+ } else {
log_debug("Removed POSIX message queue %s", fn);
+ if (ret == 0)
+ ret = 1;
+ }
}
return ret;
@@ -346,44 +385,83 @@ fail:
return log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
}
-int clean_ipc(uid_t uid, gid_t gid) {
+int clean_ipc_internal(uid_t uid, gid_t gid, bool rm) {
int ret = 0, r;
+ /* If 'rm' is true, clean all IPC objects owned by either the specified UID or the specified GID. Return the
+ * last error encountered or == 0 if no matching IPC objects have been found or > 0 if matching IPC objects
+ * have been found and have been removed.
+ *
+ * If 'rm' is false, just search for IPC objects owned by either the specified UID or the specified GID. In
+ * this case we return < 0 on error, > 0 if we found a matching object, == 0 if we didn't.
+ *
+ * As special rule: if UID/GID is specified as root we'll silently not clean up things, and always claim that
+ * there are IPC objects for it. */
+
+ if (uid == 0) {
+ if (!rm)
+ return 1;
+
+ uid = UID_INVALID;
+ }
+ if (gid == 0) {
+ if (!rm)
+ return 1;
+
+ gid = GID_INVALID;
+ }
+
/* Anything to do? */
if (!uid_is_valid(uid) && !gid_is_valid(gid))
return 0;
- /* Refuse to clean IPC of the root user */
- if (uid == 0 && gid == 0)
- return 0;
-
- r = clean_sysvipc_shm(uid, gid);
- if (r < 0)
- ret = r;
+ r = clean_sysvipc_shm(uid, gid, rm);
+ if (r != 0) {
+ if (!rm)
+ return r;
+ if (ret == 0)
+ ret = r;
+ }
- r = clean_sysvipc_sem(uid, gid);
- if (r < 0)
- ret = r;
+ r = clean_sysvipc_sem(uid, gid, rm);
+ if (r != 0) {
+ if (!rm)
+ return r;
+ if (ret == 0)
+ ret = r;
+ }
- r = clean_sysvipc_msg(uid, gid);
- if (r < 0)
- ret = r;
+ r = clean_sysvipc_msg(uid, gid, rm);
+ if (r != 0) {
+ if (!rm)
+ return r;
+ if (ret == 0)
+ ret = r;
+ }
- r = clean_posix_shm(uid, gid);
- if (r < 0)
- ret = r;
+ r = clean_posix_shm(uid, gid, rm);
+ if (r != 0) {
+ if (!rm)
+ return r;
+ if (ret == 0)
+ ret = r;
+ }
- r = clean_posix_mq(uid, gid);
- if (r < 0)
- ret = r;
+ r = clean_posix_mq(uid, gid, rm);
+ if (r != 0) {
+ if (!rm)
+ return r;
+ if (ret == 0)
+ ret = r;
+ }
return ret;
}
int clean_ipc_by_uid(uid_t uid) {
- return clean_ipc(uid, GID_INVALID);
+ return clean_ipc_internal(uid, GID_INVALID, true);
}
int clean_ipc_by_gid(gid_t gid) {
- return clean_ipc(UID_INVALID, gid);
+ return clean_ipc_internal(UID_INVALID, gid, true);
}
diff --git a/src/shared/clean-ipc.h b/src/shared/clean-ipc.h
index 6ca57f44fd..c04ed3596b 100644
--- a/src/shared/clean-ipc.h
+++ b/src/shared/clean-ipc.h
@@ -21,6 +21,15 @@
#include <sys/types.h>
-int clean_ipc(uid_t uid, gid_t gid);
+#include "user-util.h"
+
+int clean_ipc_internal(uid_t uid, gid_t gid, bool rm);
+
+/* Remove all IPC objects owned by the specified UID or GID */
int clean_ipc_by_uid(uid_t uid);
int clean_ipc_by_gid(gid_t gid);
+
+/* Check if any IPC object owned by the specified UID or GID exists, returns > 0 if so, == 0 if not */
+static inline int search_ipc(uid_t uid, gid_t gid) {
+ return clean_ipc_internal(uid, gid, false);
+}
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 1af74c61f0..74d5e854e1 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -48,6 +48,7 @@
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
+#include "process-util.h"
#include "selinux-util.h"
#include "smack-util.h"
#include "stat-util.h"
@@ -130,7 +131,7 @@ static int condition_test_kernel_command_line(Condition *c) {
const char *f;
f = startswith(word, c->parameter);
- found = f && (*f == '=' || *f == 0);
+ found = f && IN_SET(*f, 0, '=');
}
if (found)
@@ -164,7 +165,7 @@ static int condition_test_user(Condition *c) {
if (streq(username, c->parameter))
return 1;
- if (getpid() == 1)
+ if (getpid_cached() == 1)
return streq(c->parameter, "root");
u = c->parameter;
@@ -188,7 +189,7 @@ static int condition_test_group(Condition *c) {
return in_gid(id);
/* Avoid any NSS lookups if we are PID1 */
- if (getpid() == 1)
+ if (getpid_cached() == 1)
return streq(c->parameter, "root");
return in_group(c->parameter) > 0;
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index e08402e3d2..c304ae3334 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -28,8 +28,10 @@
#include "alloc-util.h"
#include "conf-files.h"
#include "conf-parser.h"
+#include "def.h"
#include "extract-word.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "log.h"
#include "macro.h"
@@ -316,24 +318,44 @@ int config_parse(const char *unit,
fd_warn_permissions(filename, fileno(f));
for (;;) {
- char buf[LINE_MAX], *l, *p, *c = NULL, *e;
+ _cleanup_free_ char *buf = NULL;
+ char *l, *p, *c = NULL, *e;
bool escaped = false;
- if (!fgets(buf, sizeof buf, f)) {
- if (feof(f))
- break;
+ r = read_line(f, LONG_LINE_MAX, &buf);
+ if (r == 0)
+ break;
+ if (r == -ENOBUFS) {
+ if (warn)
+ log_error_errno(r, "%s:%u: Line too long", filename, line);
+
+ return r;
+ }
+ if (r < 0) {
+ if (warn)
+ log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
- return log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
+ return r;
}
l = buf;
- if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK))
- l += strlen(UTF8_BYTE_ORDER_MARK);
- allow_bom = false;
+ if (allow_bom) {
+ char *q;
- truncate_nl(l);
+ q = startswith(buf, UTF8_BYTE_ORDER_MARK);
+ if (q) {
+ l = q;
+ allow_bom = false;
+ }
+ }
if (continuation) {
+ if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
+ if (warn)
+ log_error("%s:%u: Continuation line too long", filename, line);
+ return -ENOBUFS;
+ }
+
c = strappend(continuation, l);
if (!c) {
if (warn)
@@ -387,8 +409,7 @@ int config_parse(const char *unit,
if (r < 0) {
if (warn)
- log_warning_errno(r, "Failed to parse file '%s': %m",
- filename);
+ log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
return r;
}
}
@@ -436,7 +457,7 @@ int config_parse_many_nulstr(
_cleanup_strv_free_ char **files = NULL;
int r;
- r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (r < 0)
return r;
@@ -465,7 +486,7 @@ int config_parse_many(
if (r < 0)
return r;
- r = conf_files_list_strv(&files, ".conf", NULL, (const char* const*) dropin_dirs);
+ r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char* const*) dropin_dirs);
if (r < 0)
return r;
@@ -725,6 +746,11 @@ int config_parse_path(
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ n = NULL;
+ goto finalize;
+ }
+
if (!utf8_is_valid(rvalue)) {
log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return fatal ? -ENOEXEC : 0;
@@ -743,22 +769,24 @@ int config_parse_path(
path_kill_slashes(n);
+finalize:
free(*s);
*s = n;
return 0;
}
-int config_parse_strv(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_strv(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
char ***sv = data;
int r;
@@ -769,19 +797,7 @@ int config_parse_strv(const char *unit,
assert(data);
if (isempty(rvalue)) {
- char **empty;
-
- /* Empty assignment resets the list. As a special rule
- * we actually fill in a real empty array here rather
- * than NULL, since some code wants to know if
- * something was set at all... */
- empty = new0(char*, 1);
- if (!empty)
- return log_oom();
-
- strv_free(*sv);
- *sv = empty;
-
+ *sv = strv_free(*sv);
return 0;
}
@@ -803,6 +819,7 @@ int config_parse_strv(const char *unit,
free(word);
continue;
}
+
r = strv_consume(sv, word);
if (r < 0)
return log_oom();
@@ -920,10 +937,14 @@ int config_parse_personality(
assert(rvalue);
assert(personality);
- p = personality_from_string(rvalue);
- if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
- return 0;
+ if (isempty(rvalue))
+ p = PERSONALITY_INVALID;
+ else {
+ p = personality_from_string(rvalue);
+ if (p == PERSONALITY_INVALID) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
+ return 0;
+ }
}
*personality = p;
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 505a83f54f..4b59f2ca7d 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -17,7 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
#include <libcryptsetup.h>
#endif
#include <sys/mount.h>
@@ -43,7 +43,7 @@
#include "xattr-util.h"
_unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype;
int r;
@@ -57,7 +57,7 @@ _unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
errno = 0;
r = blkid_do_safeprobe(b);
- if (r == -2 || r == 1) {
+ if (IN_SET(r, -2, 1)) {
log_debug("Failed to identify any partition type on partition %s", node);
goto not_found;
}
@@ -87,7 +87,7 @@ not_found:
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) {
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
bool is_gpt, is_mbr, generic_rw, multiple_generic = false;
@@ -156,7 +156,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
errno = 0;
r = blkid_do_safeprobe(b);
- if (r == -2 || r == 1) {
+ if (IN_SET(r, -2, 1)) {
log_debug("Failed to identify any partition table.");
return -ENOPKG;
}
@@ -591,6 +591,9 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
if (streq_ptr(p->fstype, "crypto_LUKS"))
m->encrypted = true;
+
+ if (p->fstype && fstype_is_ro(p->fstype))
+ p->rw = false;
}
*ret = m;
@@ -681,7 +684,7 @@ static int mount_partition(
p = where;
/* If requested, turn on discard support. */
- if (STR_IN_SET(fstype, "btrfs", "ext4", "vfat", "xfs") &&
+ if (fstype_can_discard(fstype) &&
((flags & DISSECT_IMAGE_DISCARD) ||
((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node))))
options = "discard";
@@ -734,7 +737,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlag
return 0;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
typedef struct DecryptedPartition {
struct crypt_device *device;
char *name;
@@ -749,7 +752,7 @@ struct DecryptedImage {
#endif
DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
size_t i;
int r;
@@ -775,7 +778,7 @@ DecryptedImage* decrypted_image_unref(DecryptedImage* d) {
return NULL;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) {
_cleanup_free_ char *name = NULL, *node = NULL;
@@ -838,15 +841,19 @@ static int decrypt_partition(
r = crypt_init(&cd, m->node);
if (r < 0)
- return r;
+ return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
r = crypt_load(cd, CRYPT_LUKS1, NULL);
- if (r < 0)
+ if (r < 0) {
+ log_debug_errno(r, "Failed to load LUKS metadata: %m");
goto fail;
+ }
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
+ if (r < 0)
+ log_debug_errno(r, "Failed to activate LUKS device: %m");
if (r == -EPERM) {
r = -EKEYREJECTED;
goto fail;
@@ -945,7 +952,7 @@ int dissected_image_decrypt(
DecryptedImage **ret) {
_cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
unsigned i;
int r;
#endif
@@ -969,7 +976,7 @@ int dissected_image_decrypt(
return 0;
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
if (m->encrypted && !passphrase)
return -ENOKEY;
@@ -1051,7 +1058,7 @@ int dissected_image_decrypt_interactively(
}
}
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
static int deferred_remove(DecryptedPartition *p) {
struct dm_ioctl dm = {
@@ -1085,7 +1092,7 @@ static int deferred_remove(DecryptedPartition *p) {
int decrypted_image_relinquish(DecryptedImage *d) {
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
size_t i;
int r;
#endif
@@ -1095,7 +1102,7 @@ int decrypted_image_relinquish(DecryptedImage *d) {
/* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so
* that we don't clean it up ourselves either anymore */
-#ifdef HAVE_LIBCRYPTSETUP
+#if HAVE_LIBCRYPTSETUP
for (i = 0; i < d->n_decrypted; i++) {
DecryptedPartition *p = d->decrypted + i;
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 12c4d65dd3..4739cc880b 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -17,9 +17,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
# include <idn2.h>
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
# include <idna.h>
# include <stringprep.h>
#endif
@@ -76,7 +76,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
/* Ending NUL */
return -EINVAL;
- else if (*n == '\\' || *n == '.') {
+ else if (IN_SET(*n, '\\', '.')) {
/* Escaped backslash or dot */
if (d)
@@ -164,7 +164,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
}
terminal = *label_terminal;
- assert(*terminal == '.' || *terminal == 0);
+ assert(IN_SET(*terminal, 0, '.'));
/* Skip current terminal character (and accept domain names ending it ".") */
if (*terminal == 0)
@@ -228,7 +228,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
q = dest;
while (l > 0) {
- if (*p == '.' || *p == '\\') {
+ if (IN_SET(*p, '.', '\\')) {
/* Dot or backslash */
@@ -240,8 +240,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
sz -= 2;
- } else if (*p == '_' ||
- *p == '-' ||
+ } else if (IN_SET(*p, '_', '-') ||
(*p >= '0' && *p <= '9') ||
(*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z')) {
@@ -301,7 +300,7 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
return r;
}
-#ifdef HAVE_LIBIDN
+#if HAVE_LIBIDN
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
_cleanup_free_ uint32_t *input = NULL;
size_t input_size, l;
@@ -1272,24 +1271,47 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
int dns_name_apply_idna(const char *name, char **ret) {
/* Return negative on error, 0 if not implemented, positive on success. */
-#if defined(HAVE_LIBIDN2)
+#if HAVE_LIBIDN2
int r;
+ _cleanup_free_ char *t = NULL;
assert(name);
assert(ret);
- r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) ret,
+ r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
- if (r == IDN2_OK)
+ log_debug("idn2_lookup_u8: %s → %s", name, t);
+ if (r == IDN2_OK) {
+ if (!startswith(name, "xn--")) {
+ _cleanup_free_ char *s = NULL;
+
+ r = idn2_to_unicode_8z8z(t, &s, 0);
+ if (r != IDN2_OK) {
+ log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
+ t, r, idn2_strerror(r));
+ return 0;
+ }
+
+ if (!streq_ptr(name, s)) {
+ log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
+ name, t, s);
+ return 0;
+ }
+ }
+
+ *ret = t;
+ t = NULL;
return 1; /* *ret has been written */
- log_debug("idn2_lookup_u8(\"%s\") failed: %s", name, idn2_strerror(r));
+ }
+
+ log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
if (r == IDN2_2HYPHEN)
/* The name has two hypens — forbidden by IDNA2008 in some cases */
return 0;
if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
return -ENOSPC;
return -EINVAL;
-#elif defined(HAVE_LIBIDN)
+#elif HAVE_LIBIDN
_cleanup_free_ char *buf = NULL;
size_t n = 0, allocated = 0;
bool first = true;
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index fca025def0..a44d9d48d4 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -51,7 +51,7 @@ static inline int dns_name_parent(const char **name) {
return dns_label_unescape(name, NULL, DNS_LABEL_MAX);
}
-#if defined(HAVE_LIBIDN)
+#if HAVE_LIBIDN
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
#endif
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 15ccd1b6ca..059b50dbd0 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -187,7 +187,7 @@ int unit_file_find_dropin_paths(
Set *names,
char ***ret) {
- _cleanup_strv_free_ char **dirs = NULL, **ans = NULL;
+ _cleanup_strv_free_ char **dirs = NULL;
Iterator i;
char *t, **p;
int r;
@@ -203,12 +203,9 @@ int unit_file_find_dropin_paths(
return 0;
}
- r = conf_files_list_strv(&ans, file_suffix, NULL, (const char**) dirs);
+ r = conf_files_list_strv(ret, file_suffix, NULL, 0, (const char**) dirs);
if (r < 0)
- return log_warning_errno(r, "Failed to sort the list of configuration files: %m");
-
- *ret = ans;
- ans = NULL;
+ return log_warning_errno(r, "Failed to create the list of configuration files: %m");
return 1;
}
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index 8229e6b183..a3850bede2 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -42,7 +42,7 @@
#include "util.h"
#include "virt.h"
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
#define LOAD_OPTION_ACTIVE 0x00000001
#define MEDIA_DEVICE_PATH 0x04
@@ -269,7 +269,7 @@ int efi_set_variable(
_cleanup_close_ int fd = -1;
assert(name);
- assert(value);
+ assert(value || size == 0);
if (asprintf(&p,
"/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index b61d14c4ec..72bace0d07 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -33,7 +33,7 @@
#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004
-#ifdef ENABLE_EFI
+#if ENABLE_EFI
bool is_efi_boot(void);
bool is_efi_secure_boot(void);
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index 952fc48c45..6d295ea65b 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -72,7 +72,7 @@ static int entry_fill_basics(
}
if (source) {
entry->ip.src = source->in;
- in_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
+ in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
}
if (out_interface) {
@@ -84,7 +84,7 @@ static int entry_fill_basics(
}
if (destination) {
entry->ip.dst = destination->in;
- in_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
+ in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
}
return 0;
@@ -110,7 +110,7 @@ int fw_add_masquerade(
if (af != AF_INET)
return -EOPNOTSUPP;
- if (protocol != 0 && protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
+ if (!IN_SET(protocol, 0, IPPROTO_TCP, IPPROTO_UDP))
return -EOPNOTSUPP;
h = iptc_init("nat");
@@ -194,7 +194,7 @@ int fw_add_local_dnat(
if (af != AF_INET)
return -EOPNOTSUPP;
- if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
+ if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
return -EOPNOTSUPP;
if (local_port <= 0)
diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h
index c39b34cf8f..5915266b4b 100644
--- a/src/shared/firewall-util.h
+++ b/src/shared/firewall-util.h
@@ -24,7 +24,7 @@
#include "in-addr-util.h"
-#ifdef HAVE_LIBIPTC
+#if HAVE_LIBIPTC
int fw_add_masquerade(
bool add,
diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c
index 39b544b6f0..e10a38dcfc 100644
--- a/src/shared/gcrypt-util.c
+++ b/src/shared/gcrypt-util.c
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#include <gcrypt.h>
#include "gcrypt-util.h"
diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h
index 1da12a32be..f08ed6052c 100644
--- a/src/shared/gcrypt-util.h
+++ b/src/shared/gcrypt-util.h
@@ -23,7 +23,7 @@
#include <stdbool.h>
#include <stddef.h>
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
#include <gcrypt.h>
void initialize_libgcrypt(bool secmem);
@@ -31,7 +31,7 @@ int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);
#endif
static inline int string_hashsum_sha224(const char *s, size_t len, char **out) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
return string_hashsum(s, len, GCRY_MD_SHA224, out);
#else
return -EOPNOTSUPP;
@@ -39,7 +39,7 @@ static inline int string_hashsum_sha224(const char *s, size_t len, char **out) {
}
static inline int string_hashsum_sha256(const char *s, size_t len, char **out) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
return string_hashsum(s, len, GCRY_MD_SHA256, out);
#else
return -EOPNOTSUPP;
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 6a78ebbda7..18fc469098 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -37,6 +37,22 @@
#include "unit-name.h"
#include "util.h"
+int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src) {
+ /* Adds a symlink from <dst>.<dep_type>.d/ to ../<src> */
+
+ const char *from, *to;
+
+ from = strjoina("../", src);
+ to = strjoina(root, "/", dst, ".", dep_type, "/", src);
+
+ mkdir_parents_label(to, 0755);
+ if (symlink(from, to) < 0)
+ if (errno != EEXIST)
+ return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
+
+ return 0;
+}
+
static int write_fsck_sysroot_service(const char *dir, const char *what) {
_cleanup_free_ char *device = NULL, *escaped = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -182,6 +198,10 @@ int generator_write_timeouts(
node = fstab_node_to_udev_node(what);
if (!node)
return log_oom();
+ if (!is_device_path(node)) {
+ log_warning("x-systemd.device-timeout ignored for %s", what);
+ return 0;
+ }
r = unit_name_from_path(node, ".device", &unit);
if (r < 0)
@@ -189,8 +209,10 @@ int generator_write_timeouts(
return write_drop_in_format(dir, unit, 50, "device-timeout",
"# Automatically generated by %s\n\n"
- "[Unit]\nJobRunningTimeoutSec=%s",
- program_invocation_short_name, timeout);
+ "[Unit]\n"
+ "JobRunningTimeoutSec=%s",
+ program_invocation_short_name,
+ timeout);
}
int generator_write_device_deps(
@@ -242,6 +264,10 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
"# Automatically generated by %s\n\n"
- "[Unit]\nRequires=%s\nAfter=%s",
- program_invocation_short_name, unit, unit);
+ "[Unit]\n"
+ "Requires=%s\n"
+ "After=%s",
+ program_invocation_short_name,
+ unit,
+ unit);
}
diff --git a/src/shared/generator.h b/src/shared/generator.h
index 825d934c8e..e70016839f 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -21,6 +21,8 @@
#include <stdio.h>
+int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src);
+
int generator_write_fsck_deps(
FILE *f,
const char *dir,
diff --git a/src/shared/install.c b/src/shared/install.c
index d0a291b819..7598bf6a23 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -83,6 +83,20 @@ typedef struct {
size_t n_rules;
} Presets;
+static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) {
+ assert(i);
+
+ return !strv_isempty(i->aliases) ||
+ !strv_isempty(i->wanted_by) ||
+ !strv_isempty(i->required_by);
+}
+
+static inline bool unit_file_install_info_has_also(UnitFileInstallInfo *i) {
+ assert(i);
+
+ return !strv_isempty(i->also);
+}
+
static inline void presets_freep(Presets *p) {
size_t i;
@@ -272,7 +286,7 @@ static int path_is_vendor(const LookupPaths *p, const char *path) {
if (path_startswith(rpath, "/usr"))
return true;
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
if (path_startswith(rpath, "/lib"))
return true;
#endif
@@ -685,9 +699,35 @@ static int remove_marked_symlinks(
return r;
}
+static bool is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) {
+ int r;
+
+ if (streq(name, i->name))
+ return true;
+
+ if (strv_contains(i->aliases, name))
+ return true;
+
+ /* Look for template symlink matching DefaultInstance */
+ if (i->default_instance && unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
+ _cleanup_free_ char *s = NULL;
+
+ r = unit_name_replace_instance(i->name, i->default_instance, &s);
+ if (r < 0) {
+ if (r != -EINVAL)
+ return r;
+
+ } else if (streq(name, s))
+ return true;
+ }
+
+ return false;
+}
+
static int find_symlinks_fd(
const char *root_dir,
- const char *name,
+ UnitFileInstallInfo *i,
+ bool match_aliases,
int fd,
const char *path,
const char *config_path,
@@ -697,7 +737,7 @@ static int find_symlinks_fd(
struct dirent *de;
int r = 0;
- assert(name);
+ assert(i);
assert(fd >= 0);
assert(path);
assert(config_path);
@@ -734,7 +774,8 @@ static int find_symlinks_fd(
}
/* This will close nfd, regardless whether it succeeds or not */
- q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
+ q = find_symlinks_fd(root_dir, i, match_aliases, nfd,
+ p, config_path, same_name_link);
if (q > 0)
return 1;
if (r == 0)
@@ -774,24 +815,24 @@ static int find_symlinks_fd(
/* Check if the symlink itself matches what we
* are looking for */
- if (path_is_absolute(name))
- found_path = path_equal(p, name);
+ if (path_is_absolute(i->name))
+ found_path = path_equal(p, i->name);
else
- found_path = streq(de->d_name, name);
+ found_path = streq(de->d_name, i->name);
/* Check if what the symlink points to
* matches what we are looking for */
- if (path_is_absolute(name))
- found_dest = path_equal(dest, name);
+ if (path_is_absolute(i->name))
+ found_dest = path_equal(dest, i->name);
else
- found_dest = streq(basename(dest), name);
+ found_dest = streq(basename(dest), i->name);
if (found_path && found_dest) {
_cleanup_free_ char *t = NULL;
/* Filter out same name links in the main
* config path */
- t = path_make_absolute(name, config_path);
+ t = path_make_absolute(i->name, config_path);
if (!t)
return -ENOMEM;
@@ -800,8 +841,17 @@ static int find_symlinks_fd(
if (b)
*same_name_link = true;
- else if (found_path || found_dest)
- return 1;
+ else if (found_path || found_dest) {
+ if (!match_aliases)
+ return 1;
+
+ /* Check if symlink name is in the set of names used by [Install] */
+ q = is_symlink_with_known_name(i, de->d_name);
+ if (q < 0)
+ return q;
+ if (q > 0)
+ return 1;
+ }
}
}
@@ -810,13 +860,14 @@ static int find_symlinks_fd(
static int find_symlinks(
const char *root_dir,
- const char *name,
+ UnitFileInstallInfo *i,
+ bool match_name,
const char *config_path,
bool *same_name_link) {
int fd;
- assert(name);
+ assert(i);
assert(config_path);
assert(same_name_link);
@@ -828,12 +879,15 @@ static int find_symlinks(
}
/* This takes possession of fd and closes it */
- return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
+ return find_symlinks_fd(root_dir, i, match_name, fd,
+ config_path, config_path, same_name_link);
}
static int find_symlinks_in_scope(
+ UnitFileScope scope,
const LookupPaths *paths,
- const char *name,
+ UnitFileInstallInfo *i,
+ bool match_name,
UnitFileState *state) {
bool same_name_link_runtime = false, same_name_link_config = false;
@@ -842,12 +896,12 @@ static int find_symlinks_in_scope(
int r;
assert(paths);
- assert(name);
+ assert(i);
STRV_FOREACH(p, paths->search_path) {
bool same_name_link = false;
- r = find_symlinks(paths->root_dir, name, *p, &same_name_link);
+ r = find_symlinks(paths->root_dir, i, match_name, *p, &same_name_link);
if (r < 0)
return r;
if (r > 0) {
@@ -862,6 +916,12 @@ static int find_symlinks_in_scope(
return 1;
}
+ /* look for globally enablement of user units */
+ if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) {
+ *state = UNIT_FILE_ENABLED;
+ return 1;
+ }
+
r = path_is_runtime(paths, *p, false);
if (r < 0)
return r;
@@ -896,7 +956,7 @@ static int find_symlinks_in_scope(
* outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
* for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
* something, and hence are a much stronger concept. */
- if (enabled_at_all && unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
+ if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
*state = UNIT_FILE_STATIC;
return 1;
}
@@ -2589,13 +2649,26 @@ static int unit_file_lookup_state(
break;
}
- r = find_symlinks_in_scope(paths, i->name, &state);
+ /* Check if any of the Alias= symlinks have been created.
+ * We ignore other aliases, and only check those that would
+ * be created by systemctl enable for this unit. */
+ r = find_symlinks_in_scope(scope, paths, i, true, &state);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ break;
+
+ /* Check if the file is known under other names. If it is,
+ * it might be in use. Report that as UNIT_FILE_INDIRECT. */
+ r = find_symlinks_in_scope(scope, paths, i, false, &state);
if (r < 0)
return r;
- if (r == 0) {
- if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
+ if (r > 0)
+ state = UNIT_FILE_INDIRECT;
+ else {
+ if (unit_file_install_info_has_rules(i))
state = UNIT_FILE_DISABLED;
- else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
+ else if (unit_file_install_info_has_also(i))
state = UNIT_FILE_INDIRECT;
else
state = UNIT_FILE_STATIC;
@@ -2662,16 +2735,16 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
assert(presets);
if (scope == UNIT_FILE_SYSTEM)
- r = conf_files_list(&files, ".preset", root_dir,
+ r = conf_files_list(&files, ".preset", root_dir, 0,
"/etc/systemd/system-preset",
"/usr/local/lib/systemd/system-preset",
"/usr/lib/systemd/system-preset",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib/systemd/system-preset",
#endif
NULL);
else if (scope == UNIT_FILE_GLOBAL)
- r = conf_files_list(&files, ".preset", root_dir,
+ r = conf_files_list(&files, ".preset", root_dir, 0,
"/etc/systemd/user-preset",
"/usr/local/lib/systemd/user-preset",
"/usr/lib/systemd/user-preset",
diff --git a/src/shared/install.h b/src/shared/install.h
index 7a5859e729..c1fcbe96ed 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -132,20 +132,6 @@ struct UnitFileInstallInfo {
bool auxiliary;
};
-static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(UnitFileInstallInfo *i) {
- assert(i);
-
- return !strv_isempty(i->aliases) ||
- !strv_isempty(i->wanted_by) ||
- !strv_isempty(i->required_by);
-}
-
-static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
- assert(i);
-
- return !strv_isempty(i->also);
-}
-
bool unit_type_may_alias(UnitType type) _const_;
bool unit_type_may_template(UnitType type) _const_;
diff --git a/src/shared/journal-util.c b/src/shared/journal-util.c
index 8479221a44..fff3dfc9d1 100644
--- a/src/shared/journal-util.c
+++ b/src/shared/journal-util.c
@@ -28,7 +28,7 @@
#include "user-util.h"
static int access_check_var_log_journal(sd_journal *j) {
-#ifdef HAVE_ACL
+#if HAVE_ACL
_cleanup_strv_free_ char **g = NULL;
const char* dir;
#endif
@@ -48,7 +48,7 @@ static int access_check_var_log_journal(sd_journal *j) {
if (r > 0)
return 0;
-#ifdef HAVE_ACL
+#if HAVE_ACL
if (laccess("/run/log/journal", F_OK) >= 0)
dir = "/run/log/journal";
else
diff --git a/src/shared/libshared.sym b/src/shared/libshared.sym
new file mode 100644
index 0000000000..e4ae17eede
--- /dev/null
+++ b/src/shared/libshared.sym
@@ -0,0 +1,3 @@
+SD_SHARED {
+ global: *;
+};
diff --git a/src/shared/linux/bpf.h b/src/shared/linux/bpf.h
new file mode 100644
index 0000000000..8477b44609
--- /dev/null
+++ b/src/shared/linux/bpf.h
@@ -0,0 +1,673 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef __LINUX_BPF_H__
+#define __LINUX_BPF_H__
+
+#include <linux/types.h>
+#include <linux/bpf_common.h>
+
+/* Extended instruction set based on top of classic BPF */
+
+/* instruction classes */
+#define BPF_ALU64 0x07 /* alu mode in double word width */
+
+/* ld/ldx fields */
+#define BPF_DW 0x18 /* double word */
+#define BPF_XADD 0xc0 /* exclusive add */
+
+/* alu/jmp fields */
+#define BPF_MOV 0xb0 /* mov reg to reg */
+#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */
+
+/* change endianness of a register */
+#define BPF_END 0xd0 /* flags for endianness conversion: */
+#define BPF_TO_LE 0x00 /* convert to little-endian */
+#define BPF_TO_BE 0x08 /* convert to big-endian */
+#define BPF_FROM_LE BPF_TO_LE
+#define BPF_FROM_BE BPF_TO_BE
+
+#define BPF_JNE 0x50 /* jump != */
+#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
+#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
+#define BPF_CALL 0x80 /* function call */
+#define BPF_EXIT 0x90 /* function return */
+
+/* Register numbers */
+enum {
+ BPF_REG_0 = 0,
+ BPF_REG_1,
+ BPF_REG_2,
+ BPF_REG_3,
+ BPF_REG_4,
+ BPF_REG_5,
+ BPF_REG_6,
+ BPF_REG_7,
+ BPF_REG_8,
+ BPF_REG_9,
+ BPF_REG_10,
+ __MAX_BPF_REG,
+};
+
+/* BPF has 10 general purpose 64-bit registers and stack frame. */
+#define MAX_BPF_REG __MAX_BPF_REG
+
+struct bpf_insn {
+ __u8 code; /* opcode */
+ __u8 dst_reg:4; /* dest register */
+ __u8 src_reg:4; /* source register */
+ __s16 off; /* signed offset */
+ __s32 imm; /* signed immediate constant */
+};
+
+/* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */
+struct bpf_lpm_trie_key {
+ __u32 prefixlen; /* up to 32 for AF_INET, 128 for AF_INET6 */
+ __u8 data[0]; /* Arbitrary size */
+};
+
+/* BPF syscall commands, see bpf(2) man-page for details. */
+enum bpf_cmd {
+ BPF_MAP_CREATE,
+ BPF_MAP_LOOKUP_ELEM,
+ BPF_MAP_UPDATE_ELEM,
+ BPF_MAP_DELETE_ELEM,
+ BPF_MAP_GET_NEXT_KEY,
+ BPF_PROG_LOAD,
+ BPF_OBJ_PIN,
+ BPF_OBJ_GET,
+ BPF_PROG_ATTACH,
+ BPF_PROG_DETACH,
+ BPF_PROG_TEST_RUN,
+};
+
+enum bpf_map_type {
+ BPF_MAP_TYPE_UNSPEC,
+ BPF_MAP_TYPE_HASH,
+ BPF_MAP_TYPE_ARRAY,
+ BPF_MAP_TYPE_PROG_ARRAY,
+ BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+ BPF_MAP_TYPE_PERCPU_HASH,
+ BPF_MAP_TYPE_PERCPU_ARRAY,
+ BPF_MAP_TYPE_STACK_TRACE,
+ BPF_MAP_TYPE_CGROUP_ARRAY,
+ BPF_MAP_TYPE_LRU_HASH,
+ BPF_MAP_TYPE_LRU_PERCPU_HASH,
+ BPF_MAP_TYPE_LPM_TRIE,
+ BPF_MAP_TYPE_ARRAY_OF_MAPS,
+ BPF_MAP_TYPE_HASH_OF_MAPS,
+};
+
+enum bpf_prog_type {
+ BPF_PROG_TYPE_UNSPEC,
+ BPF_PROG_TYPE_SOCKET_FILTER,
+ BPF_PROG_TYPE_KPROBE,
+ BPF_PROG_TYPE_SCHED_CLS,
+ BPF_PROG_TYPE_SCHED_ACT,
+ BPF_PROG_TYPE_TRACEPOINT,
+ BPF_PROG_TYPE_XDP,
+ BPF_PROG_TYPE_PERF_EVENT,
+ BPF_PROG_TYPE_CGROUP_SKB,
+ BPF_PROG_TYPE_CGROUP_SOCK,
+ BPF_PROG_TYPE_LWT_IN,
+ BPF_PROG_TYPE_LWT_OUT,
+ BPF_PROG_TYPE_LWT_XMIT,
+};
+
+enum bpf_attach_type {
+ BPF_CGROUP_INET_INGRESS,
+ BPF_CGROUP_INET_EGRESS,
+ BPF_CGROUP_INET_SOCK_CREATE,
+ __MAX_BPF_ATTACH_TYPE
+};
+
+#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
+
+/* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command
+ * to the given target_fd cgroup the descendent cgroup will be able to
+ * override effective bpf program that was inherited from this cgroup
+ */
+#define BPF_F_ALLOW_OVERRIDE (1U << 0)
+
+/* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the
+ * verifier will perform strict alignment checking as if the kernel
+ * has been built with CONFIG_EFFICIENT_UNALIGNED_ACCESS not set,
+ * and NET_IP_ALIGN defined to 2.
+ */
+#define BPF_F_STRICT_ALIGNMENT (1U << 0)
+
+#define BPF_PSEUDO_MAP_FD 1
+
+/* flags for BPF_MAP_UPDATE_ELEM command */
+#define BPF_ANY 0 /* create new element or update existing */
+#define BPF_NOEXIST 1 /* create new element if it didn't exist */
+#define BPF_EXIST 2 /* update existing element */
+
+#define BPF_F_NO_PREALLOC (1U << 0)
+/* Instead of having one common LRU list in the
+ * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list
+ * which can scale and perform better.
+ * Note, the LRU nodes (including free nodes) cannot be moved
+ * across different LRU lists.
+ */
+#define BPF_F_NO_COMMON_LRU (1U << 1)
+
+union bpf_attr {
+ struct { /* anonymous struct used by BPF_MAP_CREATE command */
+ __u32 map_type; /* one of enum bpf_map_type */
+ __u32 key_size; /* size of key in bytes */
+ __u32 value_size; /* size of value in bytes */
+ __u32 max_entries; /* max number of entries in a map */
+ __u32 map_flags; /* prealloc or not */
+ __u32 inner_map_fd; /* fd pointing to the inner map */
+ };
+
+ struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
+ __u32 map_fd;
+ __aligned_u64 key;
+ union {
+ __aligned_u64 value;
+ __aligned_u64 next_key;
+ };
+ __u64 flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_LOAD command */
+ __u32 prog_type; /* one of enum bpf_prog_type */
+ __u32 insn_cnt;
+ __aligned_u64 insns;
+ __aligned_u64 license;
+ __u32 log_level; /* verbosity level of verifier */
+ __u32 log_size; /* size of user buffer */
+ __aligned_u64 log_buf; /* user supplied buffer */
+ __u32 kern_version; /* checked when prog_type=kprobe */
+ __u32 prog_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_OBJ_* commands */
+ __aligned_u64 pathname;
+ __u32 bpf_fd;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
+ __u32 target_fd; /* container object to attach to */
+ __u32 attach_bpf_fd; /* eBPF program to attach */
+ __u32 attach_type;
+ __u32 attach_flags;
+ };
+
+ struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
+ __u32 prog_fd;
+ __u32 retval;
+ __u32 data_size_in;
+ __u32 data_size_out;
+ __aligned_u64 data_in;
+ __aligned_u64 data_out;
+ __u32 repeat;
+ __u32 duration;
+ } test;
+} __attribute__((aligned(8)));
+
+/* BPF helper function descriptions:
+ *
+ * void *bpf_map_lookup_elem(&map, &key)
+ * Return: Map value or NULL
+ *
+ * int bpf_map_update_elem(&map, &key, &value, flags)
+ * Return: 0 on success or negative error
+ *
+ * int bpf_map_delete_elem(&map, &key)
+ * Return: 0 on success or negative error
+ *
+ * int bpf_probe_read(void *dst, int size, void *src)
+ * Return: 0 on success or negative error
+ *
+ * u64 bpf_ktime_get_ns(void)
+ * Return: current ktime
+ *
+ * int bpf_trace_printk(const char *fmt, int fmt_size, ...)
+ * Return: length of buffer written or negative error
+ *
+ * u32 bpf_prandom_u32(void)
+ * Return: random value
+ *
+ * u32 bpf_raw_smp_processor_id(void)
+ * Return: SMP processor ID
+ *
+ * int bpf_skb_store_bytes(skb, offset, from, len, flags)
+ * store bytes into packet
+ * @skb: pointer to skb
+ * @offset: offset within packet from skb->mac_header
+ * @from: pointer where to copy bytes from
+ * @len: number of bytes to store into packet
+ * @flags: bit 0 - if true, recompute skb->csum
+ * other bits - reserved
+ * Return: 0 on success or negative error
+ *
+ * int bpf_l3_csum_replace(skb, offset, from, to, flags)
+ * recompute IP checksum
+ * @skb: pointer to skb
+ * @offset: offset within packet where IP checksum is located
+ * @from: old value of header field
+ * @to: new value of header field
+ * @flags: bits 0-3 - size of header field
+ * other bits - reserved
+ * Return: 0 on success or negative error
+ *
+ * int bpf_l4_csum_replace(skb, offset, from, to, flags)
+ * recompute TCP/UDP checksum
+ * @skb: pointer to skb
+ * @offset: offset within packet where TCP/UDP checksum is located
+ * @from: old value of header field
+ * @to: new value of header field
+ * @flags: bits 0-3 - size of header field
+ * bit 4 - is pseudo header
+ * other bits - reserved
+ * Return: 0 on success or negative error
+ *
+ * int bpf_tail_call(ctx, prog_array_map, index)
+ * jump into another BPF program
+ * @ctx: context pointer passed to next program
+ * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY
+ * @index: index inside array that selects specific program to run
+ * Return: 0 on success or negative error
+ *
+ * int bpf_clone_redirect(skb, ifindex, flags)
+ * redirect to another netdev
+ * @skb: pointer to skb
+ * @ifindex: ifindex of the net device
+ * @flags: bit 0 - if set, redirect to ingress instead of egress
+ * other bits - reserved
+ * Return: 0 on success or negative error
+ *
+ * u64 bpf_get_current_pid_tgid(void)
+ * Return: current->tgid << 32 | current->pid
+ *
+ * u64 bpf_get_current_uid_gid(void)
+ * Return: current_gid << 32 | current_uid
+ *
+ * int bpf_get_current_comm(char *buf, int size_of_buf)
+ * stores current->comm into buf
+ * Return: 0 on success or negative error
+ *
+ * u32 bpf_get_cgroup_classid(skb)
+ * retrieve a proc's classid
+ * @skb: pointer to skb
+ * Return: classid if != 0
+ *
+ * int bpf_skb_vlan_push(skb, vlan_proto, vlan_tci)
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_vlan_pop(skb)
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_get_tunnel_key(skb, key, size, flags)
+ * int bpf_skb_set_tunnel_key(skb, key, size, flags)
+ * retrieve or populate tunnel metadata
+ * @skb: pointer to skb
+ * @key: pointer to 'struct bpf_tunnel_key'
+ * @size: size of 'struct bpf_tunnel_key'
+ * @flags: room for future extensions
+ * Return: 0 on success or negative error
+ *
+ * u64 bpf_perf_event_read(&map, index)
+ * Return: Number events read or error code
+ *
+ * int bpf_redirect(ifindex, flags)
+ * redirect to another netdev
+ * @ifindex: ifindex of the net device
+ * @flags: bit 0 - if set, redirect to ingress instead of egress
+ * other bits - reserved
+ * Return: TC_ACT_REDIRECT
+ *
+ * u32 bpf_get_route_realm(skb)
+ * retrieve a dst's tclassid
+ * @skb: pointer to skb
+ * Return: realm if != 0
+ *
+ * int bpf_perf_event_output(ctx, map, index, data, size)
+ * output perf raw sample
+ * @ctx: struct pt_regs*
+ * @map: pointer to perf_event_array map
+ * @index: index of event in the map
+ * @data: data on stack to be output as raw data
+ * @size: size of data
+ * Return: 0 on success or negative error
+ *
+ * int bpf_get_stackid(ctx, map, flags)
+ * walk user or kernel stack and return id
+ * @ctx: struct pt_regs*
+ * @map: pointer to stack_trace map
+ * @flags: bits 0-7 - numer of stack frames to skip
+ * bit 8 - collect user stack instead of kernel
+ * bit 9 - compare stacks by hash only
+ * bit 10 - if two different stacks hash into the same stackid
+ * discard old
+ * other bits - reserved
+ * Return: >= 0 stackid on success or negative error
+ *
+ * s64 bpf_csum_diff(from, from_size, to, to_size, seed)
+ * calculate csum diff
+ * @from: raw from buffer
+ * @from_size: length of from buffer
+ * @to: raw to buffer
+ * @to_size: length of to buffer
+ * @seed: optional seed
+ * Return: csum result or negative error code
+ *
+ * int bpf_skb_get_tunnel_opt(skb, opt, size)
+ * retrieve tunnel options metadata
+ * @skb: pointer to skb
+ * @opt: pointer to raw tunnel option data
+ * @size: size of @opt
+ * Return: option size
+ *
+ * int bpf_skb_set_tunnel_opt(skb, opt, size)
+ * populate tunnel options metadata
+ * @skb: pointer to skb
+ * @opt: pointer to raw tunnel option data
+ * @size: size of @opt
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_change_proto(skb, proto, flags)
+ * Change protocol of the skb. Currently supported is v4 -> v6,
+ * v6 -> v4 transitions. The helper will also resize the skb. eBPF
+ * program is expected to fill the new headers via skb_store_bytes
+ * and lX_csum_replace.
+ * @skb: pointer to skb
+ * @proto: new skb->protocol type
+ * @flags: reserved
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_change_type(skb, type)
+ * Change packet type of skb.
+ * @skb: pointer to skb
+ * @type: new skb->pkt_type type
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_under_cgroup(skb, map, index)
+ * Check cgroup2 membership of skb
+ * @skb: pointer to skb
+ * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
+ * @index: index of the cgroup in the bpf_map
+ * Return:
+ * == 0 skb failed the cgroup2 descendant test
+ * == 1 skb succeeded the cgroup2 descendant test
+ * < 0 error
+ *
+ * u32 bpf_get_hash_recalc(skb)
+ * Retrieve and possibly recalculate skb->hash.
+ * @skb: pointer to skb
+ * Return: hash
+ *
+ * u64 bpf_get_current_task(void)
+ * Returns current task_struct
+ * Return: current
+ *
+ * int bpf_probe_write_user(void *dst, void *src, int len)
+ * safely attempt to write to a location
+ * @dst: destination address in userspace
+ * @src: source address on stack
+ * @len: number of bytes to copy
+ * Return: 0 on success or negative error
+ *
+ * int bpf_current_task_under_cgroup(map, index)
+ * Check cgroup2 membership of current task
+ * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
+ * @index: index of the cgroup in the bpf_map
+ * Return:
+ * == 0 current failed the cgroup2 descendant test
+ * == 1 current succeeded the cgroup2 descendant test
+ * < 0 error
+ *
+ * int bpf_skb_change_tail(skb, len, flags)
+ * The helper will resize the skb to the given new size, to be used f.e.
+ * with control messages.
+ * @skb: pointer to skb
+ * @len: new skb length
+ * @flags: reserved
+ * Return: 0 on success or negative error
+ *
+ * int bpf_skb_pull_data(skb, len)
+ * The helper will pull in non-linear data in case the skb is non-linear
+ * and not all of len are part of the linear section. Only needed for
+ * read/write with direct packet access.
+ * @skb: pointer to skb
+ * @len: len to make read/writeable
+ * Return: 0 on success or negative error
+ *
+ * s64 bpf_csum_update(skb, csum)
+ * Adds csum into skb->csum in case of CHECKSUM_COMPLETE.
+ * @skb: pointer to skb
+ * @csum: csum to add
+ * Return: csum on success or negative error
+ *
+ * void bpf_set_hash_invalid(skb)
+ * Invalidate current skb->hash.
+ * @skb: pointer to skb
+ *
+ * int bpf_get_numa_node_id()
+ * Return: Id of current NUMA node.
+ *
+ * int bpf_skb_change_head()
+ * Grows headroom of skb and adjusts MAC header offset accordingly.
+ * Will extends/reallocae as required automatically.
+ * May change skb data pointer and will thus invalidate any check
+ * performed for direct packet access.
+ * @skb: pointer to skb
+ * @len: length of header to be pushed in front
+ * @flags: Flags (unused for now)
+ * Return: 0 on success or negative error
+ *
+ * int bpf_xdp_adjust_head(xdp_md, delta)
+ * Adjust the xdp_md.data by delta
+ * @xdp_md: pointer to xdp_md
+ * @delta: An positive/negative integer to be added to xdp_md.data
+ * Return: 0 on success or negative on error
+ *
+ * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr)
+ * Copy a NUL terminated string from unsafe address. In case the string
+ * length is smaller than size, the target is not padded with further NUL
+ * bytes. In case the string length is larger than size, just count-1
+ * bytes are copied and the last byte is set to NUL.
+ * @dst: destination address
+ * @size: maximum number of bytes to copy, including the trailing NUL
+ * @unsafe_ptr: unsafe address
+ * Return:
+ * > 0 length of the string including the trailing NUL on success
+ * < 0 error
+ *
+ * u64 bpf_get_socket_cookie(skb)
+ * Get the cookie for the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: 8 Bytes non-decreasing number on success or 0 if the socket
+ * field is missing inside sk_buff
+ *
+ * u32 bpf_get_socket_uid(skb)
+ * Get the owner uid of the socket stored inside sk_buff.
+ * @skb: pointer to skb
+ * Return: uid of the socket owner on success or overflowuid if failed.
+ */
+#define __BPF_FUNC_MAPPER(FN) \
+ FN(unspec), \
+ FN(map_lookup_elem), \
+ FN(map_update_elem), \
+ FN(map_delete_elem), \
+ FN(probe_read), \
+ FN(ktime_get_ns), \
+ FN(trace_printk), \
+ FN(get_prandom_u32), \
+ FN(get_smp_processor_id), \
+ FN(skb_store_bytes), \
+ FN(l3_csum_replace), \
+ FN(l4_csum_replace), \
+ FN(tail_call), \
+ FN(clone_redirect), \
+ FN(get_current_pid_tgid), \
+ FN(get_current_uid_gid), \
+ FN(get_current_comm), \
+ FN(get_cgroup_classid), \
+ FN(skb_vlan_push), \
+ FN(skb_vlan_pop), \
+ FN(skb_get_tunnel_key), \
+ FN(skb_set_tunnel_key), \
+ FN(perf_event_read), \
+ FN(redirect), \
+ FN(get_route_realm), \
+ FN(perf_event_output), \
+ FN(skb_load_bytes), \
+ FN(get_stackid), \
+ FN(csum_diff), \
+ FN(skb_get_tunnel_opt), \
+ FN(skb_set_tunnel_opt), \
+ FN(skb_change_proto), \
+ FN(skb_change_type), \
+ FN(skb_under_cgroup), \
+ FN(get_hash_recalc), \
+ FN(get_current_task), \
+ FN(probe_write_user), \
+ FN(current_task_under_cgroup), \
+ FN(skb_change_tail), \
+ FN(skb_pull_data), \
+ FN(csum_update), \
+ FN(set_hash_invalid), \
+ FN(get_numa_node_id), \
+ FN(skb_change_head), \
+ FN(xdp_adjust_head), \
+ FN(probe_read_str), \
+ FN(get_socket_cookie), \
+ FN(get_socket_uid),
+
+/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+ * function eBPF program intends to call
+ */
+#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
+enum bpf_func_id {
+ __BPF_FUNC_MAPPER(__BPF_ENUM_FN)
+ __BPF_FUNC_MAX_ID,
+};
+#undef __BPF_ENUM_FN
+
+/* All flags used by eBPF helper functions, placed here. */
+
+/* BPF_FUNC_skb_store_bytes flags. */
+#define BPF_F_RECOMPUTE_CSUM (1ULL << 0)
+#define BPF_F_INVALIDATE_HASH (1ULL << 1)
+
+/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags.
+ * First 4 bits are for passing the header field size.
+ */
+#define BPF_F_HDR_FIELD_MASK 0xfULL
+
+/* BPF_FUNC_l4_csum_replace flags. */
+#define BPF_F_PSEUDO_HDR (1ULL << 4)
+#define BPF_F_MARK_MANGLED_0 (1ULL << 5)
+#define BPF_F_MARK_ENFORCE (1ULL << 6)
+
+/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
+#define BPF_F_INGRESS (1ULL << 0)
+
+/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
+#define BPF_F_TUNINFO_IPV6 (1ULL << 0)
+
+/* BPF_FUNC_get_stackid flags. */
+#define BPF_F_SKIP_FIELD_MASK 0xffULL
+#define BPF_F_USER_STACK (1ULL << 8)
+#define BPF_F_FAST_STACK_CMP (1ULL << 9)
+#define BPF_F_REUSE_STACKID (1ULL << 10)
+
+/* BPF_FUNC_skb_set_tunnel_key flags. */
+#define BPF_F_ZERO_CSUM_TX (1ULL << 1)
+#define BPF_F_DONT_FRAGMENT (1ULL << 2)
+
+/* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */
+#define BPF_F_INDEX_MASK 0xffffffffULL
+#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK
+/* BPF_FUNC_perf_event_output for sk_buff input context. */
+#define BPF_F_CTXLEN_MASK (0xfffffULL << 32)
+
+/* user accessible mirror of in-kernel sk_buff.
+ * new fields can only be added to the end of this structure
+ */
+struct __sk_buff {
+ __u32 len;
+ __u32 pkt_type;
+ __u32 mark;
+ __u32 queue_mapping;
+ __u32 protocol;
+ __u32 vlan_present;
+ __u32 vlan_tci;
+ __u32 vlan_proto;
+ __u32 priority;
+ __u32 ingress_ifindex;
+ __u32 ifindex;
+ __u32 tc_index;
+ __u32 cb[5];
+ __u32 hash;
+ __u32 tc_classid;
+ __u32 data;
+ __u32 data_end;
+ __u32 napi_id;
+};
+
+struct bpf_tunnel_key {
+ __u32 tunnel_id;
+ union {
+ __u32 remote_ipv4;
+ __u32 remote_ipv6[4];
+ };
+ __u8 tunnel_tos;
+ __u8 tunnel_ttl;
+ __u16 tunnel_ext;
+ __u32 tunnel_label;
+};
+
+/* Generic BPF return codes which all BPF program types may support.
+ * The values are binary compatible with their TC_ACT_* counter-part to
+ * provide backwards compatibility with existing SCHED_CLS and SCHED_ACT
+ * programs.
+ *
+ * XDP is handled seprately, see XDP_*.
+ */
+enum bpf_ret_code {
+ BPF_OK = 0,
+ /* 1 reserved */
+ BPF_DROP = 2,
+ /* 3-6 reserved */
+ BPF_REDIRECT = 7,
+ /* >127 are reserved for prog type specific return codes */
+};
+
+struct bpf_sock {
+ __u32 bound_dev_if;
+ __u32 family;
+ __u32 type;
+ __u32 protocol;
+};
+
+#define XDP_PACKET_HEADROOM 256
+
+/* User return codes for XDP prog type.
+ * A valid XDP program must return one of these defined values. All other
+ * return codes are reserved for future use. Unknown return codes will result
+ * in packet drop.
+ */
+enum xdp_action {
+ XDP_ABORTED = 0,
+ XDP_DROP,
+ XDP_PASS,
+ XDP_TX,
+};
+
+/* user accessible metadata for XDP packet hook
+ * new fields must be added to the end of this structure
+ */
+struct xdp_md {
+ __u32 data;
+ __u32 data_end;
+};
+
+#endif /* __LINUX_BPF_H__ */
diff --git a/src/shared/linux/bpf_common.h b/src/shared/linux/bpf_common.h
new file mode 100644
index 0000000000..afe7433b98
--- /dev/null
+++ b/src/shared/linux/bpf_common.h
@@ -0,0 +1,55 @@
+#ifndef __LINUX_BPF_COMMON_H__
+#define __LINUX_BPF_COMMON_H__
+
+/* Instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_MOD 0x90
+#define BPF_XOR 0xa0
+
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+#ifndef BPF_MAXINSNS
+#define BPF_MAXINSNS 4096
+#endif
+
+#endif /* __LINUX_BPF_COMMON_H__ */
diff --git a/src/shared/linux/libbpf.h b/src/shared/linux/libbpf.h
new file mode 100644
index 0000000000..1989e3a869
--- /dev/null
+++ b/src/shared/linux/libbpf.h
@@ -0,0 +1,198 @@
+/* eBPF mini library */
+#ifndef __LIBBPF_H
+#define __LIBBPF_H
+
+#include <linux/bpf.h>
+
+struct bpf_insn;
+
+/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
+
+#define BPF_ALU64_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_ALU32_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
+
+#define BPF_ALU64_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_ALU32_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Short form of mov, dst_reg = src_reg */
+
+#define BPF_MOV64_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_MOV32_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+/* Short form of mov, dst_reg = imm32 */
+
+#define BPF_MOV64_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV32_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
+#define BPF_LD_IMM64(DST, IMM) \
+ BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_DW | BPF_IMM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = (__u32) (IMM) }), \
+ ((struct bpf_insn) { \
+ .code = 0, /* zero is reserved opcode */ \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((__u64) (IMM)) >> 32 })
+
+#ifndef BPF_PSEUDO_MAP_FD
+# define BPF_PSEUDO_MAP_FD 1
+#endif
+
+/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
+#define BPF_LD_MAP_FD(DST, MAP_FD) \
+ BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
+
+
+/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
+
+#define BPF_LD_ABS(SIZE, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
+
+#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */
+
+#define BPF_STX_XADD(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
+
+#define BPF_JMP_REG(OP, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Raw code statement block */
+
+#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = CODE, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Program exit */
+
+#define BPF_EXIT_INSN() \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_EXIT, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = 0 })
+
+#endif
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 02ae4265c6..0626d80b19 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -95,13 +95,12 @@ static int parse_field(const void *data, size_t length, const char *field, char
return 0;
nl = length - fl;
- buf = new(char, nl+1);
+
+
+ buf = newdup_suffix0(char, (const char*) data + fl, nl);
if (!buf)
return log_oom();
- memcpy(buf, (const char*) data + fl, nl);
- buf[nl] = 0;
-
free(*target);
*target = buf;
@@ -684,7 +683,7 @@ void json_escape(
fputc('\"', f);
while (l > 0) {
- if (*p == '"' || *p == '\\') {
+ if (IN_SET(*p, '"', '\\')) {
fputc('\\', f);
fputc(*p, f);
} else if (*p == '\n')
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 32a4c67590..859e5ffc1a 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -313,7 +313,7 @@ int image_find(const char *name, Image **ret) {
}
r = image_make(NULL, dirfd(d), path, name, ret);
- if (r == 0 || r == -ENOENT) {
+ if (IN_SET(r, 0, -ENOENT)) {
_cleanup_free_ char *raw = NULL;
raw = strappend(name, ".raw");
@@ -321,7 +321,7 @@ int image_find(const char *name, Image **ret) {
return -ENOMEM;
r = image_make(NULL, dirfd(d), path, raw, ret);
- if (r == 0 || r == -ENOENT)
+ if (IN_SET(r, 0, -ENOENT))
continue;
}
if (r < 0)
@@ -364,7 +364,7 @@ int image_discover(Hashmap *h) {
continue;
r = image_make(NULL, dirfd(d), path, de->d_name, &image);
- if (r == 0 || r == -ENOENT)
+ if (IN_SET(r, 0, -ENOENT))
continue;
if (r < 0)
return r;
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 2eaef11a2d..883821352e 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -104,19 +104,19 @@ shared_sources = '''
test_tables_h = files('test-tables.h')
shared_sources += [test_tables_h]
-if conf.get('HAVE_ACL', false)
+if conf.get('HAVE_ACL') == 1
shared_sources += ['acl-util.c']
endif
-if conf.get('HAVE_UTMP', false)
+if conf.get('ENABLE_UTMP') == 1
shared_sources += ['utmp-wtmp.c']
endif
-if conf.get('HAVE_SECCOMP', false)
+if conf.get('HAVE_SECCOMP') == 1
shared_sources += ['seccomp-util.c']
endif
-if conf.get('HAVE_LIBIPTC', false)
+if conf.get('HAVE_LIBIPTC') == 1
shared_sources += ['firewall-util.c']
endif
@@ -136,6 +136,8 @@ libshared_deps = [threads,
liblz4,
libblkid]
+libshared_sym_path = '@0@/libshared.sym'.format(meson.current_source_dir())
+
libshared = shared_library(
libshared_name,
shared_sources,
@@ -144,7 +146,8 @@ libshared = shared_library(
libsystemd_internal_sources,
libudev_sources,
include_directories : includes,
- link_args : ['-shared'],
+ link_args : ['-shared',
+ '-Wl,--version-script=' + libshared_sym_path],
c_args : ['-fvisibility=default'],
dependencies : libshared_deps,
install : true,
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 4d7b02c63c..0661ff0bb9 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -84,10 +84,10 @@ int pager_open(bool no_pager, bool jump_to_end) {
* pager so that we get the value from the actual tty */
(void) columns();
- if (pipe(fd) < 0)
+ if (pipe2(fd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
- parent_pid = getpid();
+ parent_pid = getpid_cached();
pager_pid = fork();
if (pager_pid < 0)
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index e2b3f8b742..802e4b9c8d 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -23,6 +23,8 @@
#include <string.h>
#include "alloc-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "install.h"
#include "log.h"
#include "macro.h"
@@ -113,6 +115,21 @@ static int user_data_dir(char **ret, const char *suffix) {
return 1;
}
+static const char* const user_data_unit_paths[] = {
+ "/usr/local/lib/systemd/user",
+ "/usr/local/share/systemd/user",
+ USER_DATA_UNIT_PATH,
+ "/usr/lib/systemd/user",
+ "/usr/share/systemd/user",
+ NULL
+};
+
+static const char* const user_config_unit_paths[] = {
+ USER_CONFIG_UNIT_PATH,
+ "/etc/systemd/user",
+ NULL
+};
+
static char** user_dirs(
const char *persistent_config,
const char *runtime_config,
@@ -123,21 +140,6 @@ static char** user_dirs(
const char *persistent_control,
const char *runtime_control) {
- const char * const config_unit_paths[] = {
- USER_CONFIG_UNIT_PATH,
- "/etc/systemd/user",
- NULL
- };
-
- const char * const data_unit_paths[] = {
- "/usr/local/lib/systemd/user",
- "/usr/local/share/systemd/user",
- USER_DATA_UNIT_PATH,
- "/usr/lib/systemd/user",
- "/usr/share/systemd/user",
- NULL
- };
-
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
_cleanup_free_ char *data_home = NULL;
_cleanup_strv_free_ char **res = NULL;
@@ -194,7 +196,7 @@ static char** user_dirs(
if (strv_extend(&res, persistent_config) < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
+ if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
return NULL;
if (strv_extend(&res, runtime_config) < 0)
@@ -209,7 +211,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
+ if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
return NULL;
if (strv_extend(&res, generator_late) < 0)
@@ -224,52 +226,62 @@ static char** user_dirs(
return tmp;
}
+bool path_is_user_data_dir(const char *path) {
+ assert(path);
+
+ return strv_contains((char**) user_data_unit_paths, path);
+}
+
+bool path_is_user_config_dir(const char *path) {
+ assert(path);
+
+ return strv_contains((char**) user_config_unit_paths, path);
+}
+
static int acquire_generator_dirs(
UnitFileScope scope,
+ const char *tempdir,
char **generator,
char **generator_early,
char **generator_late) {
+ _cleanup_(rmdir_and_freep) char *t = NULL;
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
const char *prefix;
assert(generator);
assert(generator_early);
assert(generator_late);
+ assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
- switch (scope) {
+ if (scope == UNIT_FILE_GLOBAL)
+ return -EOPNOTSUPP;
- case UNIT_FILE_SYSTEM:
- prefix = "/run/systemd/";
- break;
+ if (tempdir)
+ prefix = tempdir;
- case UNIT_FILE_USER: {
+ else if (scope == UNIT_FILE_SYSTEM)
+ prefix = "/run/systemd";
+
+ else if (scope == UNIT_FILE_USER) {
const char *e;
e = getenv("XDG_RUNTIME_DIR");
if (!e)
return -ENXIO;
- prefix = strjoina(e, "/systemd/");
- break;
- }
-
- case UNIT_FILE_GLOBAL:
- return -EOPNOTSUPP;
-
- default:
- assert_not_reached("Hmm, unexpected scope value.");
+ prefix = strjoina(e, "/systemd");
}
- x = strappend(prefix, "generator");
+ x = strappend(prefix, "/generator");
if (!x)
return -ENOMEM;
- y = strappend(prefix, "generator.early");
+ y = strappend(prefix, "/generator.early");
if (!y)
return -ENOMEM;
- z = strappend(prefix, "generator.late");
+ z = strappend(prefix, "/generator.late");
if (!z)
return -ENOMEM;
@@ -281,31 +293,30 @@ static int acquire_generator_dirs(
return 0;
}
-static int acquire_transient_dir(UnitFileScope scope, char **ret) {
- assert(ret);
-
- switch (scope) {
+static int acquire_transient_dir(
+ UnitFileScope scope,
+ const char *tempdir,
+ char **ret) {
- case UNIT_FILE_SYSTEM: {
- char *transient;
+ char *transient;
- transient = strdup("/run/systemd/transient");
- if (!transient)
- return -ENOMEM;
+ assert(ret);
+ assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
- *ret = transient;
- return 0;
- }
+ if (scope == UNIT_FILE_GLOBAL)
+ return -EOPNOTSUPP;
- case UNIT_FILE_USER:
+ if (tempdir)
+ transient = strjoin(tempdir, "/transient");
+ else if (scope == UNIT_FILE_SYSTEM)
+ transient = strdup("/run/systemd/transient");
+ else
return user_runtime_dir(ret, "/systemd/transient");
- case UNIT_FILE_GLOBAL:
- return -EOPNOTSUPP;
-
- default:
- assert_not_reached("Hmm, unexpected scope value.");
- }
+ if (!transient)
+ return -ENOMEM;
+ *ret = transient;
+ return 0;
}
static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
@@ -457,6 +468,7 @@ int lookup_paths_init(
LookupPathsFlags flags,
const char *root_dir) {
+ _cleanup_(rmdir_and_freep) char *tempdir = NULL;
_cleanup_free_ char
*root = NULL,
*persistent_config = NULL, *runtime_config = NULL,
@@ -487,6 +499,12 @@ int lookup_paths_init(
return -ENOMEM;
}
+ if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
+ r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create temporary directory: %m");
+ }
+
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
if (r < 0)
@@ -494,14 +512,15 @@ int lookup_paths_init(
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
- r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
- if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ r = acquire_generator_dirs(scope, tempdir,
+ &generator, &generator_early, &generator_late);
+ if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
return r;
}
/* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
- r = acquire_transient_dir(scope, &transient);
- if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ r = acquire_transient_dir(scope, tempdir, &transient);
+ if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
return r;
/* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
@@ -557,7 +576,7 @@ int lookup_paths_init(
"/usr/local/lib/systemd/system",
SYSTEM_DATA_UNIT_PATH,
"/usr/lib/systemd/system",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib/systemd/system",
#endif
STRV_IFNOTNULL(generator_late),
@@ -669,6 +688,9 @@ int lookup_paths_init(
p->root_dir = root;
root = NULL;
+ p->temporary_dir = tempdir;
+ tempdir = NULL;
+
return 0;
}
@@ -691,6 +713,7 @@ void lookup_paths_free(LookupPaths *p) {
p->runtime_control = mfree(p->runtime_control);
p->root_dir = mfree(p->root_dir);
+ p->temporary_dir = mfree(p->temporary_dir);
}
int lookup_paths_reduce(LookupPaths *p) {
@@ -811,6 +834,9 @@ void lookup_paths_flush_generator(LookupPaths *p) {
(void) rm_rf(p->generator_early, REMOVE_ROOT);
if (p->generator_late)
(void) rm_rf(p->generator_late, REMOVE_ROOT);
+
+ if (p->temporary_dir)
+ (void) rm_rf(p->temporary_dir, REMOVE_ROOT);
}
char **generator_binary_paths(UnitFileScope scope) {
diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h
index f9bb2fe237..fc8b8ed8c7 100644
--- a/src/shared/path-lookup.h
+++ b/src/shared/path-lookup.h
@@ -28,6 +28,7 @@ typedef struct LookupPaths LookupPaths;
typedef enum LookupPathsFlags {
LOOKUP_PATHS_EXCLUDE_GENERATED = 1,
+ LOOKUP_PATHS_TEMPORARY_GENERATED,
} LookupPathsFlags;
struct LookupPaths {
@@ -60,9 +61,14 @@ struct LookupPaths {
/* The root directory prepended to all items above, or NULL */
char *root_dir;
+
+ /* A temporary directory when running in test mode, to be nuked */
+ char *temporary_dir;
};
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
+bool path_is_user_data_dir(const char *path);
+bool path_is_user_config_dir(const char *path);
int lookup_paths_reduce(LookupPaths *p);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 59b541d519..0c92184ba5 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -187,7 +187,7 @@ static int shovel(PTYForward *f) {
if (errno == EAGAIN)
f->stdin_readable = false;
- else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
+ else if (IN_SET(errno, EIO, EPIPE, ECONNRESET)) {
f->stdin_readable = false;
f->stdin_hangup = true;
@@ -217,9 +217,9 @@ static int shovel(PTYForward *f) {
k = write(f->master, f->in_buffer, f->in_buffer_full);
if (k < 0) {
- if (errno == EAGAIN || errno == EIO)
+ if (IN_SET(errno, EAGAIN, EIO))
f->master_writable = false;
- else if (errno == EPIPE || errno == ECONNRESET) {
+ else if (IN_SET(errno, EPIPE, ECONNRESET)) {
f->master_writable = f->master_readable = false;
f->master_hangup = true;
@@ -249,7 +249,7 @@ static int shovel(PTYForward *f) {
if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f)))
f->master_readable = false;
- else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
+ else if (IN_SET(errno, EPIPE, ECONNRESET, EIO)) {
f->master_readable = f->master_writable = false;
f->master_hangup = true;
@@ -271,7 +271,7 @@ static int shovel(PTYForward *f) {
if (errno == EAGAIN)
f->stdout_writable = false;
- else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
+ else if (IN_SET(errno, EIO, EPIPE, ECONNRESET)) {
f->stdout_writable = false;
f->stdout_hangup = true;
f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 36843d4bf5..14a75bfffe 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -29,8 +29,11 @@
#include "alloc-util.h"
#include "macro.h"
#include "nsflags.h"
+#include "process-util.h"
#include "seccomp-util.h"
+#include "set.h"
#include "string-util.h"
+#include "strv.h"
#include "util.h"
#include "errno-list.h"
@@ -275,32 +278,88 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"execve\0"
"exit\0"
"exit_group\0"
+ "futex\0"
+ "get_robust_list\0"
+ "get_thread_area\0"
+ "getegid\0"
+ "getegid32\0"
+ "geteuid\0"
+ "geteuid32\0"
+ "getgid\0"
+ "getgid32\0"
+ "getgroups\0"
+ "getgroups32\0"
+ "getpgid\0"
+ "getpgrp\0"
+ "getpid\0"
+ "getppid\0"
+ "getresgid\0"
+ "getresgid32\0"
+ "getresuid\0"
+ "getresuid32\0"
"getrlimit\0" /* make sure processes can query stack size and such */
+ "getsid\0"
+ "gettid\0"
"gettimeofday\0"
+ "getuid\0"
+ "getuid32\0"
+ "membarrier\0"
"nanosleep\0"
"pause\0"
+ "prlimit64\0"
+ "restart_syscall\0"
"rt_sigreturn\0"
+ "sched_yield\0"
+ "set_robust_list\0"
+ "set_thread_area\0"
+ "set_tid_address\0"
"sigreturn\0"
"time\0"
+ "ugetrlimit\0"
+ },
+ [SYSCALL_FILTER_SET_AIO] = {
+ .name = "@aio",
+ .help = "Asynchronous IO",
+ .value =
+ "io_cancel\0"
+ "io_destroy\0"
+ "io_getevents\0"
+ "io_setup\0"
+ "io_submit\0"
},
[SYSCALL_FILTER_SET_BASIC_IO] = {
.name = "@basic-io",
.help = "Basic IO",
.value =
+ "_llseek\0"
"close\0"
+ "dup\0"
"dup2\0"
"dup3\0"
- "dup\0"
"lseek\0"
"pread64\0"
"preadv\0"
+ "preadv2\0"
"pwrite64\0"
"pwritev\0"
+ "pwritev2\0"
"read\0"
"readv\0"
"write\0"
"writev\0"
},
+ [SYSCALL_FILTER_SET_CHOWN] = {
+ .name = "@chown",
+ .help = "Change ownership of files and directories",
+ .value =
+ "chown\0"
+ "chown32\0"
+ "fchown\0"
+ "fchown32\0"
+ "fchownat\0"
+ "lchown\0"
+ "lchown32\0"
+ },
[SYSCALL_FILTER_SET_CLOCK] = {
.name = "@clock",
.help = "Change the system time",
@@ -350,24 +409,26 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"fchdir\0"
"fchmod\0"
"fchmodat\0"
- "fcntl64\0"
"fcntl\0"
+ "fcntl64\0"
"fgetxattr\0"
"flistxattr\0"
+ "fremovexattr\0"
"fsetxattr\0"
- "fstat64\0"
"fstat\0"
+ "fstat64\0"
"fstatat64\0"
- "fstatfs64\0"
"fstatfs\0"
- "ftruncate64\0"
+ "fstatfs64\0"
"ftruncate\0"
+ "ftruncate64\0"
"futimesat\0"
"getcwd\0"
- "getdents64\0"
"getdents\0"
+ "getdents64\0"
"getxattr\0"
"inotify_add_watch\0"
+ "inotify_init\0"
"inotify_init1\0"
"inotify_rm_watch\0"
"lgetxattr\0"
@@ -377,35 +438,43 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"llistxattr\0"
"lremovexattr\0"
"lsetxattr\0"
- "lstat64\0"
"lstat\0"
+ "lstat64\0"
"mkdir\0"
"mkdirat\0"
"mknod\0"
"mknodat\0"
- "mmap2\0"
"mmap\0"
+ "mmap2\0"
"munmap\0"
"newfstatat\0"
+ "oldfstat\0"
+ "oldlstat\0"
+ "oldstat\0"
"open\0"
"openat\0"
"readlink\0"
"readlinkat\0"
"removexattr\0"
"rename\0"
- "renameat2\0"
"renameat\0"
+ "renameat2\0"
"rmdir\0"
"setxattr\0"
- "stat64\0"
"stat\0"
+ "stat64\0"
"statfs\0"
+ "statfs64\0"
+#ifdef __PNR_statx
+ "statx\0"
+#endif
"symlink\0"
"symlinkat\0"
- "truncate64\0"
"truncate\0"
+ "truncate64\0"
"unlink\0"
"unlinkat\0"
+ "utime\0"
"utimensat\0"
"utimes\0"
},
@@ -414,15 +483,15 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.help = "Event loop system calls",
.value =
"_newselect\0"
- "epoll_create1\0"
"epoll_create\0"
+ "epoll_create1\0"
"epoll_ctl\0"
"epoll_ctl_old\0"
"epoll_pwait\0"
"epoll_wait\0"
"epoll_wait_old\0"
- "eventfd2\0"
"eventfd\0"
+ "eventfd2\0"
"poll\0"
"ppoll\0"
"pselect6\0"
@@ -444,8 +513,8 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"msgget\0"
"msgrcv\0"
"msgsnd\0"
- "pipe2\0"
"pipe\0"
+ "pipe2\0"
"process_vm_readv\0"
"process_vm_writev\0"
"semctl\0"
@@ -465,6 +534,16 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"keyctl\0"
"request_key\0"
},
+ [SYSCALL_FILTER_SET_MEMLOCK] = {
+ .name = "@memlock",
+ .help = "Memory locking control",
+ .value =
+ "mlock\0"
+ "mlock2\0"
+ "mlockall\0"
+ "munlock\0"
+ "munlockall\0"
+ },
[SYSCALL_FILTER_SET_MODULE] = {
.name = "@module",
.help = "Loading and unloading of kernel modules",
@@ -480,15 +559,15 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"chroot\0"
"mount\0"
"pivot_root\0"
- "umount2\0"
"umount\0"
+ "umount2\0"
},
[SYSCALL_FILTER_SET_NETWORK_IO] = {
.name = "@network-io",
.help = "Network or Unix socket IO, should not be needed if not network facing",
.value =
- "accept4\0"
"accept\0"
+ "accept4\0"
"bind\0"
"connect\0"
"getpeername\0"
@@ -523,6 +602,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"get_kernel_syms\0"
"getpmsg\0"
"gtty\0"
+ "idle\0"
"lock\0"
"mpx\0"
"prof\0"
@@ -544,41 +624,32 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.name = "@privileged",
.help = "All system calls which need super-user capabilities",
.value =
+ "@chown\0"
"@clock\0"
"@module\0"
"@raw-io\0"
+ "@reboot\0"
+ "@swap\0"
+ "_sysctl\0"
"acct\0"
"bpf\0"
"capset\0"
- "chown32\0"
- "chown\0"
"chroot\0"
- "fchown32\0"
- "fchown\0"
- "fchownat\0"
- "kexec_file_load\0"
- "kexec_load\0"
- "lchown32\0"
- "lchown\0"
"nfsservctl\0"
"pivot_root\0"
"quotactl\0"
- "reboot\0"
"setdomainname\0"
- "setfsuid32\0"
"setfsuid\0"
- "setgroups32\0"
+ "setfsuid32\0"
"setgroups\0"
+ "setgroups32\0"
"sethostname\0"
- "setresuid32\0"
"setresuid\0"
- "setreuid32\0"
+ "setresuid32\0"
"setreuid\0"
- "setuid32\0"
+ "setreuid32\0"
"setuid\0"
- "swapoff\0"
- "swapon\0"
- "_sysctl\0"
+ "setuid32\0"
"vhangup\0"
},
[SYSCALL_FILTER_SET_PROCESS] = {
@@ -586,16 +657,24 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.help = "Process control, execution, namespaceing operations",
.value =
"arch_prctl\0"
+ "capget\0" /* Able to query arbitrary processes */
"clone\0"
"execveat\0"
"fork\0"
+ "getrusage\0"
"kill\0"
"prctl\0"
+ "rt_sigqueueinfo\0"
+ "rt_tgsigqueueinfo\0"
"setns\0"
"tgkill\0"
+ "times\0"
"tkill\0"
"unshare\0"
"vfork\0"
+ "wait4\0"
+ "waitid\0"
+ "waitpid\0"
},
[SYSCALL_FILTER_SET_RAW_IO] = {
.name = "@raw-io",
@@ -617,25 +696,63 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
.name = "@reboot",
.help = "Reboot and reboot preparation/kexec",
.value =
- "kexec\0"
"kexec_file_load\0"
+ "kexec_load\0"
"reboot\0"
},
[SYSCALL_FILTER_SET_RESOURCES] = {
.name = "@resources",
.help = "Alter resource settings",
.value =
+ "ioprio_set\0"
+ "mbind\0"
+ "migrate_pages\0"
+ "move_pages\0"
+ "nice\0"
+ "sched_setaffinity\0"
+ "sched_setattr\0"
"sched_setparam\0"
"sched_setscheduler\0"
- "sched_setaffinity\0"
+ "set_mempolicy\0"
"setpriority\0"
"setrlimit\0"
- "set_mempolicy\0"
- "migrate_pages\0"
- "move_pages\0"
- "mbind\0"
- "sched_setattr\0"
- "prlimit64\0"
+ },
+ [SYSCALL_FILTER_SET_SETUID] = {
+ .name = "@setuid",
+ .help = "Operations for changing user/group credentials",
+ .value =
+ "setgid\0"
+ "setgid32\0"
+ "setgroups\0"
+ "setgroups32\0"
+ "setregid\0"
+ "setregid32\0"
+ "setresgid\0"
+ "setresgid32\0"
+ "setresuid\0"
+ "setresuid32\0"
+ "setreuid\0"
+ "setreuid32\0"
+ "setuid\0"
+ "setuid32\0"
+ },
+ [SYSCALL_FILTER_SET_SIGNAL] = {
+ .name = "@signal",
+ .help = "Process signal handling",
+ .value =
+ "rt_sigaction\0"
+ "rt_sigpending\0"
+ "rt_sigprocmask\0"
+ "rt_sigsuspend\0"
+ "rt_sigtimedwait\0"
+ "sigaction\0"
+ "sigaltstack\0"
+ "signal\0"
+ "signalfd\0"
+ "signalfd4\0"
+ "sigpending\0"
+ "sigprocmask\0"
+ "sigsuspend\0"
},
[SYSCALL_FILTER_SET_SWAP] = {
.name = "@swap",
@@ -644,6 +761,34 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"swapoff\0"
"swapon\0"
},
+ [SYSCALL_FILTER_SET_SYNC] = {
+ .name = "@sync",
+ .help = "Synchronize files and memory to storage",
+ .value =
+ "fdatasync\0"
+ "fsync\0"
+ "msync\0"
+ "sync\0"
+ "sync_file_range\0"
+ "syncfs\0"
+ },
+ [SYSCALL_FILTER_SET_TIMER] = {
+ .name = "@timer",
+ .help = "Schedule operations by time",
+ .value =
+ "alarm\0"
+ "getitimer\0"
+ "setitimer\0"
+ "timer_create\0"
+ "timer_delete\0"
+ "timer_getoverrun\0"
+ "timer_gettime\0"
+ "timer_settime\0"
+ "timerfd_create\0"
+ "timerfd_gettime\0"
+ "timerfd_settime\0"
+ "times\0"
+ },
};
const SyscallFilterSet *syscall_filter_set_find(const char *name) {
@@ -659,11 +804,52 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name) {
return NULL;
}
+static int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action, char **exclude);
+
+int seccomp_add_syscall_filter_item(scmp_filter_ctx *seccomp, const char *name, uint32_t action, char **exclude) {
+ int r;
+
+ assert(seccomp);
+ assert(name);
+
+ if (strv_contains(exclude, name))
+ return 0;
+
+ if (name[0] == '@') {
+ const SyscallFilterSet *other;
+
+ other = syscall_filter_set_find(name);
+ if (!other) {
+ log_debug("Filter set %s is not known!", name);
+ return -EINVAL;
+ }
+
+ r = seccomp_add_syscall_filter_set(seccomp, other, action, exclude);
+ if (r < 0)
+ return r;
+ } else {
+ int id;
+
+ id = seccomp_syscall_resolve_name(name);
+ if (id == __NR_SCMP_ERROR) {
+ log_debug("System call %s is not known, ignoring.", name);
+ return 0;
+ }
+
+ r = seccomp_rule_add_exact(seccomp, action, id, 0);
+ if (r < 0)
+ /* If the system call is not known on this architecture, then that's fine, let's ignore it */
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", name, id);
+ }
+
+ return 0;
+}
+
static int seccomp_add_syscall_filter_set(
scmp_filter_ctx seccomp,
- uint32_t default_action,
const SyscallFilterSet *set,
- uint32_t action) {
+ uint32_t action,
+ char **exclude) {
const char *sys;
int r;
@@ -672,28 +858,9 @@ static int seccomp_add_syscall_filter_set(
assert(set);
NULSTR_FOREACH(sys, set->value) {
- int id;
-
- if (sys[0] == '@') {
- const SyscallFilterSet *other;
-
- other = syscall_filter_set_find(sys);
- if (!other)
- return -EINVAL;
-
- r = seccomp_add_syscall_filter_set(seccomp, default_action, other, action);
- if (r < 0)
- return r;
- } else {
- id = seccomp_syscall_resolve_name(sys);
- if (id == __NR_SCMP_ERROR)
- return -EINVAL; /* Not known at all? Then that's a real error */
-
- r = seccomp_rule_add_exact(seccomp, action, id, 0);
- if (r < 0)
- /* If the system call is not known on this architecture, then that's fine, let's ignore it */
- log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", sys);
- }
+ r = seccomp_add_syscall_filter_item(seccomp, sys, action, exclude);
+ if (r < 0)
+ return r;
}
return 0;
@@ -717,7 +884,7 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
if (r < 0)
return r;
- r = seccomp_add_syscall_filter_set(seccomp, default_action, set, action);
+ r = seccomp_add_syscall_filter_set(seccomp, set, action, NULL);
if (r < 0) {
log_debug_errno(r, "Failed to add filter set, ignoring: %m");
continue;
@@ -761,7 +928,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint3
_cleanup_free_ char *n = NULL;
n = seccomp_syscall_resolve_num_arch(arch, PTR_TO_INT(id) - 1);
- log_debug_errno(r, "Failed to add rule for system call %s, ignoring: %m", strna(n));
+ log_debug_errno(r, "Failed to add rule for system call %s() / %d, ignoring: %m", strna(n), PTR_TO_INT(id) - 1);
}
}
@@ -899,6 +1066,10 @@ int seccomp_protect_sysctl(void) {
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
+ if (IN_SET(arch, SCMP_ARCH_X32, SCMP_ARCH_AARCH64))
+ /* No _sysctl syscall */
+ continue;
+
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
if (r < 0)
return r;
@@ -1041,7 +1212,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
if (r < 0)
break;
}
-
if (r < 0) {
log_debug_errno(r, "Failed to add socket() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
continue;
@@ -1066,7 +1236,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
if (r < 0)
break;
}
-
if (r < 0) {
log_debug_errno(r, "Failed to add socket() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
continue;
@@ -1219,10 +1388,6 @@ int seccomp_memory_deny_write_execute(void) {
break;
- case SCMP_ARCH_AARCH64:
- block_syscall = SCMP_SYS(mmap);
- /* fall through */
-
case SCMP_ARCH_ARM:
filter_syscall = SCMP_SYS(mmap2); /* arm has only mmap2 */
shmat_syscall = SCMP_SYS(shmat);
@@ -1230,7 +1395,8 @@ int seccomp_memory_deny_write_execute(void) {
case SCMP_ARCH_X86_64:
case SCMP_ARCH_X32:
- filter_syscall = SCMP_SYS(mmap); /* amd64 and x32 have only mmap */
+ case SCMP_ARCH_AARCH64:
+ filter_syscall = SCMP_SYS(mmap); /* amd64, x32, and arm64 have only mmap */
shmat_syscall = SCMP_SYS(shmat);
break;
@@ -1310,5 +1476,115 @@ int seccomp_restrict_archs(Set *archs) {
if (r < 0)
return r;
- return seccomp_load(seccomp);
+ r = seccomp_load(seccomp);
+ if (IN_SET(r, -EPERM, -EACCES))
+ return r;
+ if (r < 0)
+ log_debug_errno(r, "Failed to restrict system call architectures, skipping: %m");
+
+ return 0;
+}
+
+int parse_syscall_archs(char **l, Set **archs) {
+ _cleanup_set_free_ Set *_archs;
+ char **s;
+ int r;
+
+ assert(l);
+ assert(archs);
+
+ r = set_ensure_allocated(&_archs, NULL);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(s, l) {
+ uint32_t a;
+
+ r = seccomp_arch_from_string(*s, &a);
+ if (r < 0)
+ return -EINVAL;
+
+ r = set_put(_archs, UINT32_TO_PTR(a + 1));
+ if (r < 0)
+ return -ENOMEM;
+ }
+
+ *archs = _archs;
+ _archs = NULL;
+
+ return 0;
+}
+
+int seccomp_filter_set_add(Set *filter, bool add, const SyscallFilterSet *set) {
+ const char *i;
+ int r;
+
+ assert(set);
+
+ NULSTR_FOREACH(i, set->value) {
+
+ if (i[0] == '@') {
+ const SyscallFilterSet *more;
+
+ more = syscall_filter_set_find(i);
+ if (!more)
+ return -ENXIO;
+
+ r = seccomp_filter_set_add(filter, add, more);
+ if (r < 0)
+ return r;
+ } else {
+ int id;
+
+ id = seccomp_syscall_resolve_name(i);
+ if (id == __NR_SCMP_ERROR) {
+ log_debug("Couldn't resolve system call, ignoring: %s", i);
+ continue;
+ }
+
+ if (add) {
+ r = set_put(filter, INT_TO_PTR(id + 1));
+ if (r < 0)
+ return r;
+ } else
+ (void) set_remove(filter, INT_TO_PTR(id + 1));
+ }
+ }
+
+ return 0;
+}
+
+int seccomp_lock_personality(unsigned long personality) {
+ uint32_t arch;
+ int r;
+
+ if (personality >= PERSONALITY_INVALID)
+ return -EINVAL;
+
+ SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+ _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+
+ r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+ if (r < 0)
+ return r;
+
+ r = seccomp_rule_add_exact(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(personality),
+ 1,
+ SCMP_A0(SCMP_CMP_NE, personality));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add scheduler rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+ continue;
+ }
+
+ r = seccomp_load(seccomp);
+ if (IN_SET(r, -EPERM, -EACCES))
+ return r;
+ if (r < 0)
+ log_debug_errno(r, "Failed to enable personality lock for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+ }
+
+ return 0;
}
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index 4438e87fa6..6dfa465ef3 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -41,7 +41,9 @@ typedef struct SyscallFilterSet {
enum {
/* Please leave DEFAULT first, but sort the rest alphabetically */
SYSCALL_FILTER_SET_DEFAULT,
+ SYSCALL_FILTER_SET_AIO,
SYSCALL_FILTER_SET_BASIC_IO,
+ SYSCALL_FILTER_SET_CHOWN,
SYSCALL_FILTER_SET_CLOCK,
SYSCALL_FILTER_SET_CPU_EMULATION,
SYSCALL_FILTER_SET_DEBUG,
@@ -49,6 +51,7 @@ enum {
SYSCALL_FILTER_SET_IO_EVENT,
SYSCALL_FILTER_SET_IPC,
SYSCALL_FILTER_SET_KEYRING,
+ SYSCALL_FILTER_SET_MEMLOCK,
SYSCALL_FILTER_SET_MODULE,
SYSCALL_FILTER_SET_MOUNT,
SYSCALL_FILTER_SET_NETWORK_IO,
@@ -58,7 +61,11 @@ enum {
SYSCALL_FILTER_SET_RAW_IO,
SYSCALL_FILTER_SET_REBOOT,
SYSCALL_FILTER_SET_RESOURCES,
+ SYSCALL_FILTER_SET_SETUID,
+ SYSCALL_FILTER_SET_SIGNAL,
SYSCALL_FILTER_SET_SWAP,
+ SYSCALL_FILTER_SET_SYNC,
+ SYSCALL_FILTER_SET_TIMER,
_SYSCALL_FILTER_SET_MAX
};
@@ -66,6 +73,10 @@ extern const SyscallFilterSet syscall_filter_sets[];
const SyscallFilterSet *syscall_filter_set_find(const char *name);
+int seccomp_filter_set_add(Set *s, bool b, const SyscallFilterSet *set);
+
+int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude);
+
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint32_t action);
@@ -75,6 +86,7 @@ int seccomp_protect_sysctl(void);
int seccomp_restrict_address_families(Set *address_families, bool whitelist);
int seccomp_restrict_realtime(void);
int seccomp_memory_deny_write_execute(void);
+int seccomp_lock_personality(unsigned long personality);
extern const uint32_t seccomp_local_archs[];
@@ -84,3 +96,5 @@ extern const uint32_t seccomp_local_archs[];
(arch) = seccomp_local_archs[++_i])
DEFINE_TRIVIAL_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release);
+
+int parse_syscall_archs(char **l, Set **archs);
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index 7dae4d14fe..9a40147662 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -33,7 +33,7 @@
#include "time-util.h"
#include "util.h"
-#ifdef ENABLE_POLKIT
+#if ENABLE_POLKIT
static pid_t agent_pid = 0;
int polkit_agent_open(void) {
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index 1c17eb5251..81379041cc 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -107,6 +107,10 @@ int specifier_printf(const char *text, const Specifier table[], void *userdata,
*(t++) = *f;
}
+ /* if string ended with a stray %, also end with % */
+ if (percent)
+ *(t++) = '%';
+
*t = 0;
*_ret = ret;
return 0;
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index 9750dcd817..fc8548c5b3 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -234,7 +234,7 @@ int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line
if (r < 0)
return r;
- if (ut_type == LOGIN_PROCESS || ut_type == USER_PROCESS) {
+ if (IN_SET(ut_type, LOGIN_PROCESS, USER_PROCESS)) {
store.ut_type = LOGIN_PROCESS;
r = write_entry_both(&store);
if (r < 0)
diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h
index 438e270a26..8f4fbcdeff 100644
--- a/src/shared/utmp-wtmp.h
+++ b/src/shared/utmp-wtmp.h
@@ -25,7 +25,7 @@
#include "time-util.h"
#include "util.h"
-#ifdef HAVE_UTMP
+#if ENABLE_UTMP
int utmp_get_runlevel(int *runlevel, int *previous);
int utmp_put_shutdown(void);
@@ -42,7 +42,7 @@ int utmp_wall(
bool (*match_tty)(const char *tty, void *userdata),
void *userdata);
-#else /* HAVE_UTMP */
+#else /* ENABLE_UTMP */
static inline int utmp_get_runlevel(int *runlevel, int *previous) {
return -ESRCH;
@@ -71,4 +71,4 @@ static inline int utmp_wall(
return 0;
}
-#endif /* HAVE_UTMP */
+#endif /* ENABLE_UTMP */
diff --git a/src/sleep/Makefile b/src/sleep/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/sleep/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 3bac78b3e4..4d774c90b3 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -66,7 +66,7 @@ static int write_state(FILE **f, char **states) {
STRV_FOREACH(state, states) {
int k;
- k = write_string_stream(*f, *state, true);
+ k = write_string_stream(*f, *state, 0);
if (k == 0)
return 0;
log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
@@ -91,7 +91,10 @@ static int execute(char **modes, char **states) {
arg_verb,
NULL
};
- static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
+ static const char* const dirs[] = {
+ SYSTEM_SLEEP_PATH,
+ NULL
+ };
int r;
_cleanup_fclose_ FILE *f = NULL;
diff --git a/src/socket-proxy/Makefile b/src/socket-proxy/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/socket-proxy/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 1b99b7bc82..34c938438c 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -164,10 +164,10 @@ static int connection_shovel(
if (z > 0) {
*full += z;
shoveled = true;
- } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
+ } else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
*from_source = sd_event_source_unref(*from_source);
*from = safe_close(*from);
- } else if (errno != EAGAIN && errno != EINTR)
+ } else if (!IN_SET(errno, EAGAIN, EINTR))
return log_error_errno(errno, "Failed to splice: %m");
}
@@ -176,10 +176,10 @@ static int connection_shovel(
if (z > 0) {
*full -= z;
shoveled = true;
- } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
+ } else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
*to_source = sd_event_source_unref(*to_source);
*to = safe_close(*to);
- } else if (errno != EAGAIN && errno != EINTR)
+ } else if (!IN_SET(errno, EAGAIN, EINTR))
return log_error_errno(errno, "Failed to splice: %m");
}
} while (shoveled);
diff --git a/src/sulogin-shell/.gitignore b/src/sulogin-shell/.gitignore
deleted file mode 100644
index 01a315524b..0000000000
--- a/src/sulogin-shell/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-systemd-sulogin-shell
diff --git a/src/sulogin-shell/meson.build b/src/sulogin-shell/meson.build
index 4ec0d3da1a..90e6f3e716 100644
--- a/src/sulogin-shell/meson.build
+++ b/src/sulogin-shell/meson.build
@@ -1,7 +1,8 @@
-gen = configure_file(
- input : 'systemd-sulogin-shell.in',
- output : 'systemd-sulogin-shell',
- configuration : substs)
-
-install_data(gen,
- install_dir : rootlibexecdir)
+executable('systemd-sulogin-shell',
+ ['sulogin-shell.c'],
+ include_directories : includes,
+ link_with : [libshared],
+ dependencies : [],
+ install_rpath : rootlibexecdir,
+ install : true,
+ install_dir : rootlibexecdir)
diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c
new file mode 100644
index 0000000000..7933ddcc21
--- /dev/null
+++ b/src/sulogin-shell/sulogin-shell.c
@@ -0,0 +1,105 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Felipe Sateler
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <sys/prctl.h>
+
+#include "bus-util.h"
+#include "bus-error.h"
+#include "log.h"
+#include "process-util.h"
+#include "sd-bus.h"
+#include "signal-util.h"
+
+static int start_default_target(void) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ int r;
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get D-Bus connection: %m");
+ return false;
+ }
+
+ log_info("Starting default target");
+
+ /* Start these units only if we can replace base.target with it */
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartUnit",
+ &error,
+ NULL,
+ "ss", "default.target", "isolate");
+
+ if (r < 0)
+ log_error("Failed to start default target: %s", bus_error_message(&error, r));
+
+ return r;
+}
+
+static void fork_wait(const char* const cmdline[]) {
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0) {
+ log_error_errno(errno, "fork(): %m");
+ return;
+ }
+ if (pid == 0) {
+
+ /* Child */
+
+ (void) reset_all_signal_handlers();
+ (void) reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+ execv(cmdline[0], (char**) cmdline);
+ log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]);
+ _exit(EXIT_FAILURE); /* Operational error */
+ }
+
+ wait_for_terminate_and_warn(cmdline[0], pid, false);
+}
+
+static void print_mode(const char* mode) {
+ printf("You are in %s mode. After logging in, type \"journalctl -xb\" to view\n"
+ "system logs, \"systemctl reboot\" to reboot, \"systemctl default\" or ^D to boot\n"
+ "into default mode.\n", mode);
+ fflush(stdout);
+}
+
+int main(int argc, char *argv[]) {
+ static const char* const sulogin_cmdline[] = {SULOGIN, NULL};
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ print_mode(argc > 1 ? argv[1] : "");
+
+ fork_wait(sulogin_cmdline);
+
+ r = start_default_target();
+
+ return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/sulogin-shell/systemd-sulogin-shell.in b/src/sulogin-shell/systemd-sulogin-shell.in
deleted file mode 100755
index 103f841a57..0000000000
--- a/src/sulogin-shell/systemd-sulogin-shell.in
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-
-if [ -x /bin/plymouth ]; then
- /bin/plymouth --wait quit
-fi
-
-echo "You are in $1 mode. After logging in, type \"journalctl -xb\" to view"
-echo "system logs, \"systemctl reboot\" to reboot, \"systemctl default\" or ^D to boot"
-echo "into default mode."
-
-@SULOGIN@
-@SYSTEMCTL@ --job-mode=fail --no-block default
diff --git a/src/sysctl/Makefile b/src/sysctl/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/sysctl/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 6f9b42727b..a3ee6053c7 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -223,7 +223,7 @@ static int parse_argv(int argc, char *argv[]) {
* sysctl name available. */
sysctl_normalize(optarg);
- if (startswith(optarg, "/proc/sys"))
+ if (path_startswith(optarg, "/proc/sys"))
p = strdup(optarg);
else
p = strappend("/proc/sys/", optarg);
@@ -280,7 +280,7 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
- r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ r = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
if (r < 0) {
log_error_errno(r, "Failed to enumerate sysctl.d files: %m");
goto finish;
diff --git a/src/system-update-generator/Makefile b/src/system-update-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/system-update-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/systemctl/Makefile b/src/systemctl/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/systemctl/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 4a6fb5dcd1..933cb92134 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -145,7 +145,6 @@ static char *arg_root = NULL;
static usec_t arg_when = 0;
static char *argv_cmdline = NULL;
static enum action {
- _ACTION_INVALID,
ACTION_SYSTEMCTL,
ACTION_HALT,
ACTION_POWEROFF,
@@ -166,7 +165,8 @@ static enum action {
ACTION_REEXEC,
ACTION_RUNLEVEL,
ACTION_CANCEL_SHUTDOWN,
- _ACTION_MAX
+ _ACTION_MAX,
+ _ACTION_INVALID = -1
} arg_action = ACTION_SYSTEMCTL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static const char *arg_host = NULL;
@@ -1435,39 +1435,36 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
ansi_normal());
for (u = units; u < units + c; u++) {
+ const char *on_underline = NULL, *on_color = NULL, *off = NULL, *id;
_cleanup_free_ char *e = NULL;
- const char *on, *off, *on_underline = "", *off_underline = "";
- const char *id;
- bool underline = false;
+ bool underline;
+
+ underline = u + 1 < units + c &&
+ !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
- if (u + 1 < units + c &&
- !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path))) {
+ if (underline)
on_underline = ansi_underline();
- off_underline = ansi_normal();
- underline = true;
- }
if (IN_SET(u->state,
UNIT_FILE_MASKED,
UNIT_FILE_MASKED_RUNTIME,
UNIT_FILE_DISABLED,
UNIT_FILE_BAD))
- on = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
+ on_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
else if (u->state == UNIT_FILE_ENABLED)
- on = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
- else
- on = on_underline;
- off = off_underline;
+ on_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
+
+ if (on_underline || on_color)
+ off = ansi_normal();
id = basename(u->path);
e = arg_full ? NULL : ellipsize(id, id_cols, 33);
- printf("%s%-*s %s%-*s%s%s\n",
- on_underline,
+ printf("%s%-*s %s%-*s%s\n",
+ strempty(on_underline),
id_cols, e ? e : id,
- on, state_cols, unit_file_state_to_string(u->state), off,
- off_underline);
+ strempty(on_color), state_cols, unit_file_state_to_string(u->state), strempty(off));
}
if (!arg_no_legend)
@@ -2010,7 +2007,7 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
for (m = machine_infos; m < machine_infos + n; m++) {
namelen = MAX(namelen, strlen(m->name) + (m->is_host ? sizeof(" (host)") - 1 : 0));
- statelen = MAX(statelen, m->state ? strlen(m->state) : 0);
+ statelen = MAX(statelen, strlen_ptr(m->state));
failedlen = MAX(failedlen, DECIMAL_STR_WIDTH(m->n_failed_units));
jobslen = MAX(jobslen, DECIMAL_STR_WIDTH(m->n_jobs));
@@ -2480,7 +2477,6 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
assert(lp);
assert(unit_name);
- assert(unit_path);
STRV_FOREACH(p, lp->search_path) {
_cleanup_free_ char *path = NULL, *lpath = NULL;
@@ -2498,14 +2494,48 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
if (r < 0)
return log_error_errno(r, "Failed to access path '%s': %m", path);
- *unit_path = lpath;
- lpath = NULL;
+ if (unit_path) {
+ *unit_path = lpath;
+ lpath = NULL;
+ }
return 1;
}
return 0;
}
+static int unit_find_template_path(
+ const char *unit_name,
+ LookupPaths *lp,
+ char **fragment_path,
+ char **template) {
+
+ _cleanup_free_ char *_template = NULL;
+ int r;
+
+ /* Returns 1 if a fragment was found, 0 if not found, negative on error. */
+
+ r = unit_file_find_path(lp, unit_name, fragment_path);
+ if (r != 0)
+ return r; /* error or found a real unit */
+
+ r = unit_name_template(unit_name, &_template);
+ if (r == -EINVAL)
+ return 0; /* not a template, does not exist */
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine template name: %m");
+
+ r = unit_file_find_path(lp, _template, fragment_path);
+ if (r < 0)
+ return r;
+
+ if (template) {
+ *template = _template;
+ _template = NULL;
+ }
+ return r;
+}
+
static int unit_find_paths(
sd_bus *bus,
const char *unit_name,
@@ -2561,29 +2591,18 @@ static int unit_find_paths(
return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
}
} else {
- _cleanup_set_free_ Set *names;
+ _cleanup_set_free_ Set *names = NULL;
_cleanup_free_ char *template = NULL;
names = set_new(NULL);
if (!names)
return log_oom();
- r = unit_file_find_path(lp, unit_name, &path);
+ r = unit_find_template_path(unit_name, lp, &path, &template);
if (r < 0)
return r;
- if (r == 0) {
- r = unit_name_template(unit_name, &template);
- if (r < 0 && r != -EINVAL)
- return log_error_errno(r, "Failed to determine template name: %m");
- if (r >= 0) {
- r = unit_file_find_path(lp, template, &path);
- if (r < 0)
- return r;
- }
- }
-
- if (path)
+ if (r > 0)
/* We found the unit file. If we followed symlinks, this name might be
* different then the unit_name with started with. Look for dropins matching
* that "final" name. */
@@ -3052,7 +3071,7 @@ static const struct {
static enum action verb_to_action(const char *verb) {
enum action i;
- for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
+ for (i = 0; i < _ACTION_MAX; i++)
if (streq_ptr(action_table[i].verb, verb))
return i;
@@ -3068,8 +3087,8 @@ static int start_unit(int argc, char *argv[], void *userdata) {
char **name;
int r = 0;
- if (arg_wait && !strstr(argv[0], "start")) {
- log_error("--wait may only be used with a command that starts units.");
+ if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
+ log_error("--wait may only be used with the 'start' or 'restart' commands.");
return -EINVAL;
}
@@ -3085,22 +3104,30 @@ static int start_unit(int argc, char *argv[], void *userdata) {
if (arg_action == ACTION_SYSTEMCTL) {
enum action action;
- method = verb_to_method(argv[0]);
action = verb_to_action(argv[0]);
- if (streq(argv[0], "isolate")) {
- mode = "isolate";
- suffix = ".target";
- } else
- mode = action_table[action].mode ?: arg_job_mode;
+ if (action != _ACTION_INVALID) {
+ method = "StartUnit";
+ mode = action_table[action].mode;
+ one_name = action_table[action].target;
+ } else {
+ if (streq(argv[0], "isolate")) {
+ method = "StartUnit";
+ mode = "isolate";
- one_name = action_table[action].target;
+ suffix = ".target";
+ } else {
+ method = verb_to_method(argv[0]);
+ mode = arg_job_mode;
+ }
+ one_name = NULL;
+ }
} else {
- assert(arg_action < ELEMENTSOF(action_table));
+ assert(arg_action >= 0 && arg_action < _ACTION_MAX);
assert(action_table[arg_action].target);
+ assert(action_table[arg_action].mode);
method = "StartUnit";
-
mode = action_table[arg_action].mode;
one_name = action_table[arg_action].target;
}
@@ -3192,7 +3219,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
return r;
}
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
static int logind_set_wall_message(void) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
@@ -3228,7 +3255,7 @@ static int logind_set_wall_message(void) {
/* Ask systemd-logind, which might grant access to unprivileged users
* through PolicyKit */
static int logind_reboot(enum action a) {
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method, *description;
sd_bus *bus;
@@ -3240,14 +3267,19 @@ static int logind_reboot(enum action a) {
switch (a) {
+ case ACTION_POWEROFF:
+ method = "PowerOff";
+ description = "power off system";
+ break;
+
case ACTION_REBOOT:
method = "Reboot";
description = "reboot system";
break;
- case ACTION_POWEROFF:
- method = "PowerOff";
- description = "power off system";
+ case ACTION_HALT:
+ method = "Halt";
+ description = "halt system";
break;
case ACTION_SUSPEND:
@@ -3291,7 +3323,7 @@ static int logind_reboot(enum action a) {
}
static int logind_check_inhibitors(enum action a) {
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **sessions = NULL;
const char *what, *who, *why, *mode;
@@ -3348,8 +3380,10 @@ static int logind_check_inhibitors(enum action a) {
if (!sv)
return log_oom();
- if ((pid_t) pid < 0)
- return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
+ if (!pid_is_valid((pid_t) pid)) {
+ log_error("Invalid PID "PID_FMT".", (pid_t) pid);
+ return -ERANGE;
+ }
if (!strv_contains(sv,
IN_SET(a,
@@ -3410,7 +3444,7 @@ static int logind_check_inhibitors(enum action a) {
}
static int logind_prepare_firmware_setup(void) {
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
int r;
@@ -3539,6 +3573,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
if (IN_SET(a,
ACTION_POWEROFF,
ACTION_REBOOT,
+ ACTION_HALT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP)) {
@@ -3550,8 +3585,16 @@ static int start_special(int argc, char *argv[], void *userdata) {
/* requested operation is not supported or already in progress */
return r;
- /* On all other errors, try low-level operation */
- }
+ /* On all other errors, try low-level operation. In order to minimize the difference between
+ * operation with and without logind, we explicitly enable non-blocking mode for this, as
+ * logind's shutdown operations are always non-blocking. */
+
+ arg_no_block = true;
+
+ } else if (IN_SET(a, ACTION_EXIT, ACTION_KEXEC))
+ /* Since exit/kexec are so close in behaviour to power-off/reboot, let's also make them
+ * asynchronous, in order to not confuse the user needlessly with unexpected behaviour. */
+ arg_no_block = true;
r = start_unit(argc, argv, userdata);
}
@@ -3849,6 +3892,9 @@ typedef struct UnitStatusInfo {
uint64_t tasks_current;
uint64_t tasks_max;
+ uint64_t ip_ingress_bytes;
+ uint64_t ip_egress_bytes;
+
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
@@ -4165,6 +4211,14 @@ static void print_status_info(
if (i->status_errno > 0)
printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
+ if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
+ char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
+
+ printf(" IP: %s in, %s out\n",
+ format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
+ format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
+ }
+
if (i->tasks_current != (uint64_t) -1) {
printf(" Tasks: %" PRIu64, i->tasks_current);
@@ -4455,6 +4509,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->next_elapse_monotonic = u;
else if (streq(name, "NextElapseUSecRealtime"))
i->next_elapse_real = u;
+ else if (streq(name, "IPIngressBytes"))
+ i->ip_ingress_bytes = u;
+ else if (streq(name, "IPEgressBytes"))
+ i->ip_egress_bytes = u;
break;
}
@@ -4969,6 +5027,8 @@ static int show_one(
.cpu_usage_nsec = (uint64_t) -1,
.tasks_current = (uint64_t) -1,
.tasks_max = (uint64_t) -1,
+ .ip_ingress_bytes = (uint64_t) -1,
+ .ip_egress_bytes = (uint64_t) -1,
};
int r;
@@ -5857,7 +5917,7 @@ static int import_environment(int argc, char *argv[], void *userdata) {
static int enable_sysv_units(const char *verb, char **args) {
int r = 0;
-#if defined(HAVE_SYSV_COMPAT)
+#if HAVE_SYSV_COMPAT
_cleanup_lookup_paths_free_ LookupPaths paths = {};
unsigned f = 0;
@@ -6084,7 +6144,7 @@ static int normalize_names(char **names, bool warn_if_path) {
return 0;
}
-static int unit_exists(const char *unit) {
+static int unit_exists(LookupPaths *lp, const char *unit) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *path = NULL;
@@ -6097,6 +6157,9 @@ static int unit_exists(const char *unit) {
sd_bus *bus;
int r;
+ if (unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
+ return unit_find_template_path(unit, lp, NULL, NULL);
+
path = unit_dbus_path_from_name(unit);
if (!path)
return log_oom();
@@ -6222,11 +6285,20 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
sd_bus *bus;
if (STR_IN_SET(verb, "mask", "unmask")) {
- r = unit_exists(*names);
+ char **name;
+ _cleanup_lookup_paths_free_ LookupPaths lp = {};
+
+ r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
if (r < 0)
return r;
- if (r == 0)
- log_notice("Unit %s does not exist, proceeding anyway.", *names);
+
+ STRV_FOREACH(name, names) {
+ r = unit_exists(&lp, *name);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ log_notice("Unit %s does not exist, proceeding anyway.", *names);
+ }
}
r = acquire_bus(BUS_MANAGER, &bus);
@@ -7280,11 +7352,6 @@ static void help_states(void) {
puts(automount_state_to_string(i));
if (!arg_no_legend)
- puts("\nAvailable busname unit substates:");
- for (i = 0; i < _BUSNAME_STATE_MAX; i++)
- puts(busname_state_to_string(i));
-
- if (!arg_no_legend)
puts("\nAvailable device unit substates:");
for (i = 0; i < _DEVICE_STATE_MAX; i++)
puts(device_state_to_string(i));
@@ -7783,7 +7850,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
assert(argv);
if (utmp_get_runlevel(&runlevel, NULL) >= 0)
- if (runlevel == '0' || runlevel == '6')
+ if (IN_SET(runlevel, '0', '6'))
arg_force = 2;
while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
@@ -8188,7 +8255,7 @@ static int parse_argv(int argc, char *argv[]) {
return systemctl_parse_argv(argc, argv);
}
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
_pure_ static int action_to_runlevel(void) {
static const char table[_ACTION_MAX] = {
@@ -8202,14 +8269,14 @@ _pure_ static int action_to_runlevel(void) {
[ACTION_RESCUE] = '1'
};
- assert(arg_action < _ACTION_MAX);
+ assert(arg_action >= 0 && arg_action < _ACTION_MAX);
return table[arg_action];
}
#endif
static int talk_initctl(void) {
-#ifdef HAVE_SYSV_COMPAT
+#if HAVE_SYSV_COMPAT
struct init_request request = {
.magic = INIT_MAGIC,
.sleeptime = 0,
@@ -8403,7 +8470,7 @@ static int halt_now(enum action a) {
static int logind_schedule_shutdown(void) {
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char date[FORMAT_TIMESTAMP_MAX];
const char *action;
@@ -8480,7 +8547,7 @@ static int halt_main(void) {
/* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown
* the machine. */
- if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT, ACTION_HALT)) {
r = logind_reboot(arg_action);
if (r >= 0)
return r;
@@ -8532,7 +8599,7 @@ static int runlevel_main(void) {
}
static int logind_cancel_shutdown(void) {
-#ifdef ENABLE_LOGIND
+#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
int r;
@@ -8597,6 +8664,10 @@ int main(int argc, char*argv[]) {
r = systemctl_main(argc, argv);
break;
+ /* Legacy command aliases set arg_action. They provide some fallbacks,
+ * e.g. to tell sysvinit to reboot after you have installed systemd
+ * binaries. */
+
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
@@ -8609,8 +8680,6 @@ int main(int argc, char*argv[]) {
case ACTION_RUNLEVEL4:
case ACTION_RUNLEVEL5:
case ACTION_RESCUE:
- case ACTION_EMERGENCY:
- case ACTION_DEFAULT:
r = start_with_fallback();
break;
@@ -8627,6 +8696,15 @@ int main(int argc, char*argv[]) {
r = runlevel_main();
break;
+ case ACTION_EXIT:
+ case ACTION_SUSPEND:
+ case ACTION_HIBERNATE:
+ case ACTION_HYBRID_SLEEP:
+ case ACTION_EMERGENCY:
+ case ACTION_DEFAULT:
+ /* systemctl verbs with no equivalent in the legacy commands.
+ * These cannot appear in arg_action. Fall through. */
+
case _ACTION_INVALID:
default:
assert_not_reached("Unknown action");
diff --git a/src/systemd/Makefile b/src/systemd/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/systemd/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index f731fdcbd4..5e46d8d0e8 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -58,9 +58,17 @@ enum {
SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
SD_DHCP_OPTION_INTERFACE_MTU = 26,
SD_DHCP_OPTION_BROADCAST = 28,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_ROUTER_DISCOVER = 31,
SD_DHCP_OPTION_STATIC_ROUTE = 33,
SD_DHCP_OPTION_NTP_SERVER = 42,
SD_DHCP_OPTION_VENDOR_SPECIFIC = 43,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_NAMESERVER = 44,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_NODETYPE = 46,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_SCOPE = 47,
SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
SD_DHCP_OPTION_OVERLOAD = 52,
@@ -79,6 +87,10 @@ enum {
SD_DHCP_OPTION_DOMAIN_SEARCH_LIST = 119,
SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
SD_DHCP_OPTION_PRIVATE_BASE = 224,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252,
SD_DHCP_OPTION_PRIVATE_LAST = 254,
SD_DHCP_OPTION_END = 255,
};
@@ -146,7 +158,9 @@ int sd_dhcp_client_start(sd_dhcp_client *client);
sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
-int sd_dhcp_client_new(sd_dhcp_client **ret);
+/* NOTE: anonymize parameter is used to initialize PRL memory with different
+ * options when using RFC7844 Anonymity Profiles */
+int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize);
int sd_dhcp_client_attach_event(
sd_dhcp_client *client,
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index f466d9b062..8c23486779 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -99,6 +99,13 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_UNIT_RELOADED SD_ID128_MAKE(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
#define SD_MESSAGE_UNIT_RELOADED_STR SD_ID128_MAKE_STR(7b,05,eb,c6,68,38,42,22,ba,a8,88,11,79,cf,da,54)
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED SD_ID128_MAKE(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+#define SD_MESSAGE_UNIT_RESTART_SCHEDULED_STR \
+ SD_ID128_MAKE_STR(5e,b0,34,94,b6,58,48,70,a5,36,b3,37,29,08,09,b3)
+
+#define SD_MESSAGE_UNIT_RESOURCES SD_ID128_MAKE(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+#define SD_MESSAGE_UNIT_RESOURCES_STR SD_ID128_MAKE_STR(ae,8f,7b,86,6b,03,47,b9,af,31,fe,1c,80,b1,27,c0)
+
#define SD_MESSAGE_SPAWN_FAILED SD_ID128_MAKE(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
#define SD_MESSAGE_SPAWN_FAILED_STR SD_ID128_MAKE_STR(64,12,57,65,1c,1b,4e,c9,a8,62,4d,7a,40,a9,e1,e7)
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index 3f5a6673cf..b28fc0da00 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -138,6 +138,7 @@ int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags);
int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table);
+int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type);
int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family);
@@ -147,6 +148,7 @@ int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
+int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type);
int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags);
int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state);
@@ -159,6 +161,18 @@ int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, ui
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
+int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family);
+int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos);
+int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, unsigned char *tos);
+int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table);
+int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, unsigned char *table);
+int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len);
+int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(sd_netlink_message *m, unsigned char *len);
+int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len);
+int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char *len);
+int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type);
+int sd_rtnl_message_routing_policy_rule_get_rtm_type(sd_netlink_message *m, unsigned char *type);
+
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);
diff --git a/src/systemd/sd-radv.h b/src/systemd/sd-radv.h
index 4cbd80db68..0cc1d670b9 100644
--- a/src/systemd/sd-radv.h
+++ b/src/systemd/sd-radv.h
@@ -57,6 +57,9 @@ int sd_radv_set_managed_information(sd_radv *ra, int managed);
int sd_radv_set_other_information(sd_radv *ra, int other);
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
+int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
+ const struct in6_addr *dns, size_t n_dns);
+int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);
/* Advertised prefixes */
int sd_radv_prefix_new(sd_radv_prefix **ret);
diff --git a/src/sysusers/Makefile b/src/sysusers/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/sysusers/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index fbe51a6ed5..6ef00d8f25 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -233,8 +233,14 @@ static int make_backup(const char *target, const char *x) {
if (futimens(fileno(dst), ts) < 0)
log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup);
- if (rename(temp, backup) < 0)
+ r = fflush_sync_and_check(dst);
+ if (r < 0)
+ goto fail;
+
+ if (rename(temp, backup) < 0) {
+ r = -errno;
goto fail;
+ }
return 0;
@@ -293,7 +299,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) {
return 0;
}
-#ifdef ENABLE_GSHADOW
+#if ENABLE_GSHADOW
static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
char **a;
@@ -532,7 +538,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
return errno ? -errno : -EIO;
}
- r = fflush_and_check(shadow);
+ r = fflush_sync_and_check(shadow);
if (r < 0)
return r;
@@ -616,7 +622,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
group_changed = true;
}
- r = fflush_and_check(group);
+ r = fflush_sync_and_check(group);
if (r < 0)
return r;
@@ -630,7 +636,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
}
static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, char **tmpfile_path) {
-#ifdef ENABLE_GSHADOW
+#if ENABLE_GSHADOW
_cleanup_fclose_ FILE *original = NULL, *gshadow = NULL;
_cleanup_(unlink_and_freep) char *gshadow_tmp = NULL;
bool group_changed = false;
@@ -693,7 +699,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
group_changed = true;
}
- r = fflush_and_check(gshadow);
+ r = fflush_sync_and_check(gshadow);
if (r < 0)
return r;
@@ -1663,7 +1669,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
v++;
l = strstrip(line);
- if (*l == '#' || *l == 0)
+ if (IN_SET(*l, 0, '#'))
continue;
k = parse_line(fn, v, l);
@@ -1792,7 +1798,7 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
- r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
+ r = conf_files_list_nulstr(&files, ".conf", arg_root, 0, conf_file_dirs);
if (r < 0) {
log_error_errno(r, "Failed to enumerate sysusers.d files: %m");
goto finish;
@@ -1805,6 +1811,16 @@ int main(int argc, char *argv[]) {
}
}
+ /* Let's tell nss-systemd not to synthesize the "root" and "nobody" entries for it, so that our detection
+ * whether the names or UID/GID area already used otherwise doesn't get confused. After all, even though
+ * nss-systemd synthesizes these users/groups, they should still appear in /etc/passwd and /etc/group, as the
+ * synthesizing logic is merely supposed to be fallback for cases where we run with a completely unpopulated
+ * /etc. */
+ if (setenv("SYSTEMD_NSS_BYPASS_SYNTHETIC", "1", 1) < 0) {
+ r = log_error_errno(errno, "Failed to set SYSTEMD_NSS_BYPASS_SYNTHETIC environment variable: %m");
+ goto finish;
+ }
+
if (!uid_range) {
/* Default to default range of 1..SYSTEMD_UID_MAX */
r = uid_range_add(&uid_range, &n_uid_range, 1, SYSTEM_UID_MAX);
diff --git a/src/sysv-generator/Makefile b/src/sysv-generator/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/sysv-generator/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 9828078443..195f7a0604 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -28,6 +28,7 @@
#include "exit-status.h"
#include "fd-util.h"
#include "fileio.h"
+#include "generator.h"
#include "hashmap.h"
#include "hexdecoct.h"
#include "install.h"
@@ -101,29 +102,6 @@ static void free_sysvstub_hashmapp(Hashmap **h) {
hashmap_free(*h);
}
-static int add_symlink(const char *service, const char *where) {
- const char *from, *to;
- int r;
-
- assert(service);
- assert(where);
-
- from = strjoina(arg_dest, "/", service);
- to = strjoina(arg_dest, "/", where, ".wants/", service);
-
- mkdir_parents_label(to, 0755);
-
- r = symlink(from, to);
- if (r < 0) {
- if (errno == EEXIST)
- return 0;
-
- return -errno;
- }
-
- return 1;
-}
-
static int add_alias(const char *service, const char *alias) {
const char *link;
int r;
@@ -219,11 +197,8 @@ static int generate_unit_file(SysvStub *s) {
if (r < 0)
return log_error_errno(r, "Failed to write unit %s: %m", unit);
- STRV_FOREACH(p, s->wanted_by) {
- r = add_symlink(s->name, *p);
- if (r < 0)
- log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
- }
+ STRV_FOREACH(p, s->wanted_by)
+ (void) generator_add_symlink(arg_dest, *p, "wants", s->name);
return 1;
}
@@ -505,7 +480,7 @@ static int load_sysv(SysvStub *s) {
continue;
}
- if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
+ if (IN_SET(state, LSB_DESCRIPTION, LSB) && streq(t, "### END INIT INFO")) {
state = NORMAL;
continue;
}
@@ -579,7 +554,7 @@ static int load_sysv(SysvStub *s) {
chkconfig_description = d;
}
- } else if (state == LSB || state == LSB_DESCRIPTION) {
+ } else if (IN_SET(state, LSB, LSB_DESCRIPTION)) {
if (startswith_no_case(t, "Provides:")) {
state = LSB;
diff --git a/src/test/.gitignore b/src/test/.gitignore
deleted file mode 100644
index e4c198a4f7..0000000000
--- a/src/test/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-test-hashmap-ordered.c
diff --git a/src/test/Makefile b/src/test/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/test/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/test/meson.build b/src/test/meson.build
index 7b493a4d05..1f3db65781 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -42,7 +42,8 @@ tests += [
[],
[]],
- [['src/test/test-engine.c'],
+ [['src/test/test-engine.c',
+ 'src/test/test-helper.c'],
[libcore,
libudev,
libsystemd_internal],
@@ -105,7 +106,8 @@ tests += [
[],
'ENABLE_EFI'],
- [['src/test/test-unit-name.c'],
+ [['src/test/test-unit-name.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -115,7 +117,8 @@ tests += [
libmount,
libblkid]],
- [['src/test/test-unit-file.c'],
+ [['src/test/test-unit-file.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -274,6 +277,10 @@ tests += [
[],
[]],
+ [['src/test/test-in-addr-util.c'],
+ [],
+ []],
+
[['src/test/test-barrier.c'],
[],
[]],
@@ -332,6 +339,17 @@ tests += [
[libbasic],
[]],
+ [['src/test/test-bpf.c',
+ 'src/test/test-helper.c'],
+ [libcore,
+ libshared],
+ [libmount,
+ threads,
+ librt,
+ libseccomp,
+ libselinux,
+ libblkid]],
+
[['src/test/test-hashmap.c',
'src/test/test-hashmap-plain.c',
test_hashmap_ordered_c],
@@ -456,7 +474,8 @@ tests += [
'', 'manual'],
- [['src/test/test-cgroup-mask.c'],
+ [['src/test/test-cgroup-mask.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -486,7 +505,8 @@ tests += [
[],
[]],
- [['src/test/test-path.c'],
+ [['src/test/test-path.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -496,7 +516,8 @@ tests += [
libmount,
libblkid]],
- [['src/test/test-execute.c'],
+ [['src/test/test-execute.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -524,7 +545,8 @@ tests += [
[],
[]],
- [['src/test/test-sched-prio.c'],
+ [['src/test/test-sched-prio.c',
+ 'src/test/test-helper.c'],
[libcore,
libshared],
[threads,
@@ -756,21 +778,10 @@ tests += [
[],
[]],
- [['src/libsystemd/sd-bus/test-bus-kernel.c'],
- [],
- []],
-
- [['src/libsystemd/sd-bus/test-bus-kernel-bloom.c'],
- [],
- []],
-
[['src/libsystemd/sd-bus/test-bus-benchmark.c'],
[],
- [threads]],
-
- [['src/libsystemd/sd-bus/test-bus-zero-copy.c'],
- [],
- []],
+ [threads],
+ '', 'manual'],
[['src/libsystemd/sd-bus/test-bus-introspect.c'],
[],
diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c
index f41e488d99..68975b790a 100644
--- a/src/test/test-architecture.c
+++ b/src/test/test-architecture.c
@@ -26,7 +26,7 @@ int main(int argc, char *argv[]) {
int a, v;
v = detect_virtualization();
- if (v == -EPERM || v == -EACCES)
+ if (IN_SET(v, -EPERM, -EACCES))
return EXIT_TEST_SKIP;
assert_se(v >= 0);
diff --git a/src/test/test-bpf.c b/src/test/test-bpf.c
new file mode 100644
index 0000000000..74e9d50561
--- /dev/null
+++ b/src/test/test-bpf.c
@@ -0,0 +1,162 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Daniel Mack
+
+ 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 <linux/libbpf.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "bpf-firewall.h"
+#include "bpf-program.h"
+#include "load-fragment.h"
+#include "manager.h"
+#include "rm-rf.h"
+#include "service.h"
+#include "test-helper.h"
+#include "tests.h"
+#include "unit.h"
+
+int main(int argc, char *argv[]) {
+ struct bpf_insn exit_insn[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 1),
+ BPF_EXIT_INSN()
+ };
+
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
+ CGroupContext *cc = NULL;
+ _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
+ Manager *m = NULL;
+ Unit *u;
+ char log_buf[65535];
+ int r;
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ enter_cgroup_subroot();
+ assert_se(set_unit_path(get_testdata_dir("")) >= 0);
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+
+ r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, &p);
+ assert(r == 0);
+
+ r = bpf_program_add_instructions(p, exit_insn, ELEMENTSOF(exit_insn));
+ assert(r == 0);
+
+ if (getuid() != 0) {
+ log_notice("Not running as root, skipping kernel related tests.");
+ return EXIT_TEST_SKIP;
+ }
+
+ r = bpf_firewall_supported();
+ if (r == 0) {
+ log_notice("BPF firewalling not supported, skipping");
+ return EXIT_TEST_SKIP;
+ }
+ assert_se(r > 0);
+
+ r = bpf_program_load_kernel(p, log_buf, ELEMENTSOF(log_buf));
+ assert(r >= 0);
+
+ p = bpf_program_unref(p);
+
+ /* The simple tests suceeded. Now let's try full unit-based use-case. */
+
+ assert_se(manager_new(UNIT_FILE_USER, true, &m) >= 0);
+ assert_se(manager_startup(m, NULL, NULL) >= 0);
+
+ assert_se(u = unit_new(m, sizeof(Service)));
+ assert_se(unit_add_name(u, "foo.service") == 0);
+ assert_se(cc = unit_get_cgroup_context(u));
+ u->perpetual = true;
+
+ cc->ip_accounting = true;
+
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "10.0.1.0/24", &cc->ip_address_allow, NULL) == 0);
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressAllow", 0, "127.0.0.2", &cc->ip_address_allow, NULL) == 0);
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.3", &cc->ip_address_deny, NULL) == 0);
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "10.0.3.2/24", &cc->ip_address_deny, NULL) == 0);
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.1/25", &cc->ip_address_deny, NULL) == 0);
+ assert_se(config_parse_ip_address_access(u->id, "filename", 1, "Service", 1, "IPAddressDeny", 0, "127.0.0.4", &cc->ip_address_deny, NULL) == 0);
+
+ assert(cc->ip_address_allow);
+ assert(cc->ip_address_allow->items_next);
+ assert(!cc->ip_address_allow->items_next->items_next);
+
+ /* The deny list is defined redundantly, let's ensure it got properly reduced */
+ assert(cc->ip_address_deny);
+ assert(cc->ip_address_deny->items_next);
+ assert(!cc->ip_address_deny->items_next->items_next);
+
+ assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/usr/bin/ping -c 1 127.0.0.2 -W 5", SERVICE(u)->exec_command, u) == 0);
+ assert_se(config_parse_exec(u->id, "filename", 1, "Service", 1, "ExecStart", SERVICE_EXEC_START, "/usr/bin/ping -c 1 127.0.0.3 -W 5", SERVICE(u)->exec_command, u) == 0);
+
+ assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]);
+ assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next);
+ assert_se(!SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->command_next);
+
+ SERVICE(u)->type = SERVICE_ONESHOT;
+ u->load_state = UNIT_LOADED;
+
+ unit_dump(u, stdout, NULL);
+
+ r = bpf_firewall_compile(u);
+ if (IN_SET(r, -ENOTTY, -ENOSYS, -EPERM )) {
+ /* Kernel doesn't support the necessary bpf bits, or masked out via seccomp? */
+ manager_free(m);
+ return EXIT_TEST_SKIP;
+ }
+ assert_se(r >= 0);
+
+ assert(u->ip_bpf_ingress);
+ assert(u->ip_bpf_egress);
+
+ r = bpf_program_load_kernel(u->ip_bpf_ingress, log_buf, ELEMENTSOF(log_buf));
+
+ log_notice("log:");
+ log_notice("-------");
+ log_notice("%s", log_buf);
+ log_notice("-------");
+
+ assert(r >= 0);
+
+ r = bpf_program_load_kernel(u->ip_bpf_egress, log_buf, ELEMENTSOF(log_buf));
+
+ log_notice("log:");
+ log_notice("-------");
+ log_notice("%s", log_buf);
+ log_notice("-------");
+
+ assert(r >= 0);
+
+ assert(unit_start(u) >= 0);
+
+ while (!IN_SET(SERVICE(u)->state, SERVICE_DEAD, SERVICE_FAILED))
+ assert_se(sd_event_run(m->event, UINT64_MAX) >= 0);
+
+ assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.code == CLD_EXITED &&
+ SERVICE(u)->exec_command[SERVICE_EXEC_START]->exec_status.status == EXIT_SUCCESS);
+
+ assert_se(SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.code != CLD_EXITED ||
+ SERVICE(u)->exec_command[SERVICE_EXEC_START]->command_next->exec_status.status != EXIT_SUCCESS);
+
+ manager_free(m);
+
+ return 0;
+}
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index a026ce4ef1..bd5bebe66d 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -170,6 +170,8 @@ int main(int argc, char* argv[]) {
test_one("annually", "*-01-01 00:00:00");
test_one("*:2/3", "*-*-* *:02/3:00");
test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+ test_one("2015-10-25 01:00:00 Asia/Vladivostok", "2015-10-25 01:00:00 Asia/Vladivostok");
+ test_one("weekly Pacific/Auckland", "Mon *-*-* 00:00:00 Pacific/Auckland");
test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001");
test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000");
test_one("9..11,13:00,30", "*-*-* 09..11,13:00,30:00");
@@ -219,6 +221,16 @@ int main(int argc, char* argv[]) {
test_next("2017-08-06 9,11,13,15,17:00 UTC", "", 1502029800000000, 1502031600000000);
test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000);
test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000);
+ test_next("2017-09-24 03:30:00 Pacific/Auckland", "", 12345, 1506177000000000);
+ // Due to daylight saving time - 2017-09-24 02:30:00 does not exist
+ test_next("2017-09-24 02:30:00 Pacific/Auckland", "", 12345, -1);
+ test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 12345, 1491053400000000);
+ // Confirm that even though it's a time change here (backward) 02:30 happens only once
+ test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 1491053400000000, -1);
+ test_next("2017-04-02 03:30:00 Pacific/Auckland", "", 12345, 1491060600000000);
+ // Confirm that timezones in the Spec work regardless of current timezone
+ test_next("2017-09-09 20:42:00 Pacific/Auckland", "", 12345, 1504946520000000);
+ test_next("2017-09-09 20:42:00 Pacific/Auckland", "EET", 12345, 1504946520000000);
assert_se(calendar_spec_from_string("test", &c) < 0);
assert_se(calendar_spec_from_string(" utc", &c) < 0);
diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c
index 4132ec56fd..c1af277f34 100644
--- a/src/test/test-cap-list.c
+++ b/src/test/test-cap-list.c
@@ -24,6 +24,7 @@
#include "capability-util.h"
#include "fileio.h"
#include "parse-util.h"
+#include "string-util.h"
#include "util.h"
/* verify the capability parser */
@@ -102,10 +103,24 @@ static void test_last_cap_probe(void) {
assert_se(p == cap_last_cap());
}
+static void test_capability_set_to_string_alloc(void) {
+ _cleanup_free_ char *t1 = NULL, *t2 = NULL, *t3 = NULL;
+
+ assert_se(capability_set_to_string_alloc(0u, &t1) == 0);
+ assert_se(streq(t1, ""));
+
+ assert_se(capability_set_to_string_alloc(1u<<CAP_DAC_OVERRIDE, &t2) == 0);
+ assert_se(streq(t2, "cap_dac_override"));
+
+ assert_se(capability_set_to_string_alloc(UINT64_C(1)<<CAP_CHOWN | UINT64_C(1)<<CAP_DAC_OVERRIDE | UINT64_C(1)<<CAP_DAC_READ_SEARCH | UINT64_C(1)<<CAP_FOWNER | UINT64_C(1)<<CAP_SETGID | UINT64_C(1)<<CAP_SETUID | UINT64_C(1)<<CAP_SYS_PTRACE | UINT64_C(1)<<CAP_SYS_ADMIN | UINT64_C(1)<<CAP_AUDIT_CONTROL | UINT64_C(1)<<CAP_MAC_OVERRIDE | UINT64_C(1)<<CAP_SYSLOG, &t3) == 0);
+ assert_se(streq(t3, "cap_chown cap_dac_override cap_dac_read_search cap_fowner cap_setgid cap_setuid cap_sys_ptrace cap_sys_admin cap_audit_control cap_mac_override cap_syslog"));
+}
+
int main(int argc, char *argv[]) {
test_cap_list();
test_last_cap_file();
test_last_cap_probe();
+ test_capability_set_to_string_alloc();
return 0;
}
diff --git a/src/test/test-capability.c b/src/test/test-capability.c
index 629bb63c81..8276c75987 100644
--- a/src/test/test-capability.c
+++ b/src/test/test-capability.c
@@ -205,6 +205,8 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported()));
+
if (getuid() != 0)
return EXIT_TEST_SKIP;
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index b42088c680..02aae84152 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -34,11 +34,13 @@ static int test_cgroup_mask(void) {
FDSet *fdset = NULL;
int r;
+ enter_cgroup_subroot();
+
/* Prepare the manager. */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
- r = manager_new(UNIT_FILE_USER, true, &m);
- if (r == -EPERM || r == -EACCES) {
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
+ if (IN_SET(r, -EPERM, -EACCES)) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
}
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 30cd463722..d5bc73feff 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -192,8 +192,7 @@ static void test_proc(void) {
pid_t pid;
uid_t uid = UID_INVALID;
- if (de->d_type != DT_DIR &&
- de->d_type != DT_UNKNOWN)
+ if (!IN_SET(de->d_type, DT_DIR, DT_UNKNOWN))
continue;
r = parse_pid(de->d_name, &pid);
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 5336c19652..71e318a15b 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -35,19 +35,19 @@ int main(int argc, char*argv[]) {
assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-c") == 0);
assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0) == 0);
- assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid_cached(), &path) == 0);
assert_se(streq(path, "/test-b"));
free(path);
assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) == 0);
- assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid_cached(), &path) == 0);
assert_se(path_equal(path, "/test-a"));
free(path);
assert_se(cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, "/test-b/test-d", 0) == 0);
- assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid(), &path) == 0);
+ assert_se(cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, getpid_cached(), &path) == 0);
assert_se(path_equal(path, "/test-b/test-d"));
free(path);
diff --git a/src/test/test-clock.c b/src/test/test-clock.c
index 7d97328416..94f8b50f41 100644
--- a/src/test/test-clock.c
+++ b/src/test/test-clock.c
@@ -66,7 +66,7 @@ static void test_clock_is_localtime(void) {
log_info("%s", scenarios[i].contents);
rewind(f);
ftruncate(fd, 0);
- assert_se(write_string_stream(f, scenarios[i].contents, false) == 0);
+ assert_se(write_string_stream(f, scenarios[i].contents, WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result);
}
@@ -82,7 +82,7 @@ static void test_clock_is_localtime_system(void) {
log_info("/etc/adjtime exists, clock_is_localtime() == %i", r);
/* if /etc/adjtime exists we expect some answer, no error or
* crash */
- assert_se(r == 0 || r == 1);
+ assert_se(IN_SET(r, 0, 1));
} else
/* default is UTC if there is no /etc/adjtime */
assert_se(r == 0);
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index 121345cfd1..278ac2ab6c 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -390,7 +390,7 @@ static void test_condition_test_user(void) {
assert_se(condition);
r = condition_test(condition);
log_info("ConditionUser=@system → %i", r);
- if (geteuid() == 0)
+ if (getuid() < SYSTEM_UID_MAX || geteuid() < SYSTEM_UID_MAX)
assert_se(r > 0);
else
assert_se(r == 0);
@@ -402,7 +402,7 @@ static void test_condition_test_group(void) {
char* gid;
char* groupname;
gid_t *gids, max_gid;
- int ngroups_max, r, i;
+ int ngroups_max, ngroups, r, i;
assert_se(0 < asprintf(&gid, "%u", UINT32_C(0xFFFF)));
condition = condition_new(CONDITION_GROUP, gid, false, false);
@@ -427,11 +427,11 @@ static void test_condition_test_group(void) {
gids = alloca(sizeof(gid_t) * ngroups_max);
- r = getgroups(ngroups_max, gids);
- assert(r >= 0);
+ ngroups = getgroups(ngroups_max, gids);
+ assert(ngroups >= 0);
max_gid = getgid();
- for (i = 0; i < r; i++) {
+ for (i = 0; i < ngroups; i++) {
assert_se(0 < asprintf(&gid, "%u", gids[i]));
condition = condition_new(CONDITION_GROUP, gid, false, false);
assert_se(condition);
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index 22b7c61204..777b5ca32b 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -75,7 +75,7 @@ static void test_conf_files_list(bool use_root) {
log_debug("/* Check when filtered by suffix */");
- assert_se(conf_files_list(&found_files, ".conf", root_dir, search_1, search_2, NULL) == 0);
+ assert_se(conf_files_list(&found_files, ".conf", root_dir, 0, search_1, search_2, NULL) == 0);
strv_print(found_files);
assert_se(found_files);
@@ -84,7 +84,7 @@ static void test_conf_files_list(bool use_root) {
assert_se(found_files[2] == NULL);
log_debug("/* Check when unfiltered */");
- assert_se(conf_files_list(&found_files2, NULL, root_dir, search_1, search_2, NULL) == 0);
+ assert_se(conf_files_list(&found_files2, NULL, root_dir, 0, search_1, search_2, NULL) == 0);
strv_print(found_files2);
assert_se(found_files2);
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 77fcbc0dd3..7a7de98bec 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -18,6 +18,8 @@
***/
#include "conf-parser.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "log.h"
#include "macro.h"
#include "string-util.h"
@@ -25,12 +27,10 @@
#include "util.h"
static void test_config_parse_path_one(const char *rvalue, const char *expected) {
- char *path = NULL;
+ _cleanup_free_ char *path = NULL;
assert_se(config_parse_path("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &path, NULL) >= 0);
assert_se(streq_ptr(expected, path));
-
- free(path);
}
static void test_config_parse_log_level_one(const char *rvalue, int expected) {
@@ -76,12 +76,10 @@ static void test_config_parse_unsigned_one(const char *rvalue, unsigned expected
}
static void test_config_parse_strv_one(const char *rvalue, char **expected) {
- char **strv = 0;
+ _cleanup_strv_free_ char **strv = NULL;
assert_se(config_parse_strv("unit", "filename", 1, "section", 1, "lvalue", 0, rvalue, &strv, NULL) >= 0);
assert_se(strv_equal(expected, strv));
-
- strv_free(strv);
}
static void test_config_parse_mode_one(const char *rvalue, mode_t expected) {
@@ -227,7 +225,130 @@ static void test_config_parse_iec_uint64(void) {
assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
}
+#define x10(x) x x x x x x x x x x
+#define x100(x) x10(x10(x))
+#define x1000(x) x10(x100(x))
+
+static const char* const config_file[] = {
+ "[Section]\n"
+ "setting1=1\n",
+
+ "[Section]\n"
+ "setting1=1", /* no terminating newline */
+
+ "\n\n\n\n[Section]\n\n\n"
+ "setting1=1", /* some whitespace, no terminating newline */
+
+ "[Section]\n"
+ "[Section]\n"
+ "setting1=1\n"
+ "setting1=2\n"
+ "setting1=1\n", /* repeated settings */
+
+ "[Section]\n"
+ "setting1=1\\\n" /* normal continuation */
+ "2\\\n"
+ "3\n",
+
+ "[Section]\n"
+ "setting1=1\\\\\\\n" /* continuation with trailing escape symbols */
+ "\\\\2\n", /* note that C requires one level of escaping, so the
+ * parser gets "…1 BS BS BS NL BS BS 2 NL", which
+ * it translates into "…1 BS BS SP BS BS 2" */
+
+ "\n[Section]\n\n"
+ "setting1=" /* a line above LINE_MAX length */
+ x1000("ABCD")
+ "\n",
+
+ "[Section]\n"
+ "setting1=" /* a line above LINE_MAX length, with continuation */
+ x1000("ABCD") "\\\n"
+ "foobar",
+
+ "[Section]\n"
+ "setting1=" /* a line above the allowed limit: 9 + 1050000 + 1 */
+ x1000(x1000("x") x10("abcde")) "\n",
+
+ "[Section]\n"
+ "setting1=" /* many continuation lines, together above the limit */
+ x1000(x1000("x") x10("abcde") "\\\n") "xxx",
+};
+
+static void test_config_parse(unsigned i, const char *s) {
+ char name[] = "/tmp/test-conf-parser.XXXXXX";
+ int fd, r;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *setting1 = NULL;
+
+ const ConfigTableItem items[] = {
+ { "Section", "setting1", config_parse_string, 0, &setting1},
+ {}
+ };
+
+ log_info("== %s[%i] ==", __func__, i);
+
+ fd = mkostemp_safe(name);
+ assert_se(fd >= 0);
+ assert_se((size_t) write(fd, s, strlen(s)) == strlen(s));
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(f = fdopen(fd, "r"));
+
+ /*
+ int config_parse(const char *unit,
+ const char *filename,
+ FILE *f,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ bool allow_include,
+ bool warn,
+ void *userdata)
+ */
+
+ r = config_parse(NULL, name, f,
+ "Section\0",
+ config_item_table_lookup, items,
+ false, false, true, NULL);
+
+ switch (i) {
+ case 0 ... 3:
+ assert_se(r == 0);
+ assert_se(streq(setting1, "1"));
+ break;
+
+ case 4:
+ assert_se(r == 0);
+ assert_se(streq(setting1, "1 2 3"));
+ break;
+
+ case 5:
+ assert_se(r == 0);
+ assert_se(streq(setting1, "1\\\\ \\\\2"));
+ break;
+
+ case 6:
+ assert_se(r == 0);
+ assert_se(streq(setting1, x1000("ABCD")));
+ break;
+
+ case 7:
+ assert_se(r == 0);
+ assert_se(streq(setting1, x1000("ABCD") " foobar"));
+ break;
+
+ case 8 ... 9:
+ assert_se(r == -ENOBUFS);
+ assert_se(setting1 == NULL);
+ break;
+ }
+}
+
int main(int argc, char **argv) {
+ unsigned i;
+
log_parse_environment();
log_open();
@@ -244,5 +365,8 @@ int main(int argc, char **argv) {
test_config_parse_nsec();
test_config_parse_iec_uint64();
+ for (i = 0; i < ELEMENTSOF(config_file); i++)
+ test_config_parse(i, config_file[i]);
+
return 0;
}
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index ed6725611d..187baa2d53 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -220,6 +220,14 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
else
assert_se(IN_SET(r, 0, 1));
+ assert_se(fstat(fd, &buf) == 0);
+ assert_se(fstat(fd2, &buf2) == 0);
+ assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes));
+
+ if (max_bytes < (uint64_t) -1)
+ /* Make sure the file is now higher than max_bytes */
+ assert_se(ftruncate(fd2, max_bytes + 1) == 0);
+
assert_se(lseek(fd2, 0, SEEK_SET) == 0);
r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0);
@@ -233,12 +241,12 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
* are copying is exactly max_bytes bytes. */
assert_se(r == 1);
- assert_se(fstat(fd, &buf) == 0);
- assert_se(fstat(fd2, &buf2) == 0);
assert_se(fstat(fd3, &buf3) == 0);
- assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes));
- assert_se(buf3.st_size == buf2.st_size);
+ if (max_bytes == (uint64_t) -1)
+ assert_se(buf3.st_size == buf2.st_size);
+ else
+ assert_se((uint64_t) buf3.st_size == max_bytes);
unlink(fn2);
unlink(fn3);
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
index 8818d1ffb7..e510633584 100644
--- a/src/test/test-cpu-set-util.c
+++ b/src/test/test-cpu-set-util.c
@@ -130,7 +130,7 @@ static void test_parse_cpu_set(void) {
assert_se(ncpus == 0); /* empty string returns 0 */
assert_se(!c);
- /* Runnaway quoted string */
+ /* Runaway quoted string */
ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus < 0);
assert_se(!c);
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
index a7cb426282..e5887cc06a 100644
--- a/src/test/test-daemon.c
+++ b/src/test/test-daemon.c
@@ -21,11 +21,20 @@
#include "sd-daemon.h"
+#include "parse-util.h"
#include "strv.h"
int main(int argc, char*argv[]) {
_cleanup_strv_free_ char **l = NULL;
int n, i;
+ usec_t duration = USEC_PER_SEC / 10;
+
+ if (argc >= 2) {
+ unsigned x;
+
+ assert_se(safe_atou(argv[1], &x) >= 0);
+ duration = x * USEC_PER_SEC;
+ }
n = sd_listen_fds_with_names(false, &l);
if (n < 0) {
@@ -38,27 +47,27 @@ int main(int argc, char*argv[]) {
sd_notify(0,
"STATUS=Starting up");
- sleep(1);
+ usleep(duration);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
- sleep(1);
+ usleep(duration);
sd_notify(0,
"STATUS=Reloading\n"
"RELOADING=1");
- sleep(1);
+ usleep(duration);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
- sleep(1);
+ usleep(duration);
sd_notify(0,
"STATUS=Quitting\n"
"STOPPING=1");
- sleep(1);
+ usleep(duration);
return EXIT_SUCCESS;
}
diff --git a/src/test/test-date.c b/src/test/test-date.c
index 0e7d44fade..c09d615396 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -33,6 +33,12 @@ static void test_should_pass(const char *p) {
log_info("\"%s\" → \"%s\"", p, buf);
assert_se(parse_timestamp(buf, &q) >= 0);
+ if (q != t) {
+ char tmp[FORMAT_TIMESTAMP_MAX];
+
+ log_error("round-trip failed: \"%s\" → \"%s\"",
+ buf, format_timestamp_us(tmp, sizeof(tmp), q));
+ }
assert_se(q == t);
assert_se(format_timestamp_relative(buf_relative, sizeof(buf_relative), t));
@@ -77,6 +83,10 @@ static void test_one_noutc(const char *p) {
}
int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
test_one("17:41");
test_one("18:42:44");
test_one("18:42:44.0");
@@ -90,6 +100,10 @@ int main(int argc, char *argv[]) {
test_one("yesterday");
test_one("today");
test_one("tomorrow");
+ test_one_noutc("16:20 UTC");
+ test_one_noutc("16:20 Asia/Seoul");
+ test_one_noutc("tomorrow Asia/Seoul");
+ test_one_noutc("2012-12-30 18:42 Asia/Seoul");
test_one_noutc("now");
test_one_noutc("+2d");
test_one_noutc("+2y 4d");
@@ -100,6 +114,9 @@ int main(int argc, char *argv[]) {
test_should_fail("1969-12-31 UTC");
test_should_fail("-100y");
test_should_fail("today UTC UTC");
+ test_should_fail("now Asia/Seoul");
+ test_should_fail("+2d Asia/Seoul");
+ test_should_fail("@1395716396 Asia/Seoul");
#if SIZEOF_TIME_T == 8
test_should_pass("9999-12-30 23:59:59 UTC");
test_should_fail("9999-12-31 00:00:00 UTC");
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 11cf0b1f0b..75bc5e4a73 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -615,13 +615,16 @@ static void test_dns_name_apply_idna_one(const char *s, int expected, const char
log_debug("dns_name_apply_idna: \"%s\" → %d/\"%s\" (expected %d/\"%s\")",
s, r, strnull(buf), expected, strnull(result));
- assert_se(r == expected);
+ /* Different libidn2 versions are more and less accepting
+ * of underscore-prefixed names. So let's list the lowest
+ * expected return value. */
+ assert_se(r >= expected);
if (expected == 1)
assert_se(dns_name_equal(buf, result) == 1);
}
static void test_dns_name_apply_idna(void) {
-#if defined HAVE_LIBIDN2 || defined HAVE_LIBIDN
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
const int ret = 1;
#else
const int ret = 0;
@@ -635,7 +638,7 @@ static void test_dns_name_apply_idna(void) {
* labels. If registrars follow IDNA2008 we'll just be performing a
* useless lookup.
*/
-#if defined HAVE_LIBIDN
+#if HAVE_LIBIDN
const int ret2 = 1;
#else
const int ret2 = 0;
@@ -652,6 +655,12 @@ static void test_dns_name_apply_idna(void) {
test_dns_name_apply_idna_one("föö.bär.", ret, "xn--f-1gaa.xn--br-via");
test_dns_name_apply_idna_one("xn--f-1gaa.xn--br-via", ret, "xn--f-1gaa.xn--br-via");
+ test_dns_name_apply_idna_one("_443._tcp.fedoraproject.org", ret2,
+ "_443._tcp.fedoraproject.org");
+ test_dns_name_apply_idna_one("_443", ret2, "_443");
+ test_dns_name_apply_idna_one("gateway", ret, "gateway");
+ test_dns_name_apply_idna_one("_gateway", ret2, "_gateway");
+
test_dns_name_apply_idna_one("r3---sn-ab5l6ne7.googlevideo.com", ret2,
ret2 ? "r3---sn-ab5l6ne7.googlevideo.com" : "");
}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index 8133343fb3..6916f838d4 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -37,10 +37,12 @@ int main(int argc, char *argv[]) {
Job *j;
int r;
+ enter_cgroup_subroot();
+
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
- r = manager_new(UNIT_FILE_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
diff --git a/src/test/test-exec-util.c b/src/test/test-exec-util.c
index 30c92019d9..c192d3522c 100644
--- a/src/test/test-exec-util.c
+++ b/src/test/test-exec-util.c
@@ -71,10 +71,14 @@ static const gather_stdout_callback_t ignore_stdout[] = {
};
static void test_execute_directory(bool gather_stdout) {
- char template_lo[] = "/tmp/test-exec-util.XXXXXXX";
- char template_hi[] = "/tmp/test-exec-util.XXXXXXX";
+ char template_lo[] = "/tmp/test-exec-util.lo.XXXXXXX";
+ char template_hi[] = "/tmp/test-exec-util.hi.XXXXXXX";
const char * dirs[] = {template_hi, template_lo, NULL};
- const char *name, *name2, *name3, *overridden, *override, *masked, *mask;
+ const char *name, *name2, *name3,
+ *overridden, *override,
+ *masked, *mask,
+ *masked2, *mask2, /* the mask is non-executable */
+ *masked2e, *mask2e; /* the mask is executable */
log_info("/* %s (%s) */", __func__, gather_stdout ? "gathering stdout" : "asynchronous");
@@ -88,6 +92,10 @@ static void test_execute_directory(bool gather_stdout) {
override = strjoina(template_hi, "/overridden");
masked = strjoina(template_lo, "/masked");
mask = strjoina(template_hi, "/masked");
+ masked2 = strjoina(template_lo, "/masked2");
+ mask2 = strjoina(template_hi, "/masked2");
+ masked2e = strjoina(template_lo, "/masked2e");
+ mask2e = strjoina(template_hi, "/masked2e");
assert_se(write_string_file(name,
"#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works",
@@ -104,7 +112,15 @@ static void test_execute_directory(bool gather_stdout) {
assert_se(write_string_file(masked,
"#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(masked2,
+ "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
+ WRITE_STRING_FILE_CREATE) == 0);
+ assert_se(write_string_file(masked2e,
+ "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed",
+ WRITE_STRING_FILE_CREATE) == 0);
assert_se(symlink("/dev/null", mask) == 0);
+ assert_se(touch(mask2) == 0);
+ assert_se(touch(mask2e) == 0);
assert_se(touch(name3) >= 0);
assert_se(chmod(name, 0755) == 0);
@@ -112,6 +128,9 @@ static void test_execute_directory(bool gather_stdout) {
assert_se(chmod(overridden, 0755) == 0);
assert_se(chmod(override, 0755) == 0);
assert_se(chmod(masked, 0755) == 0);
+ assert_se(chmod(masked2, 0755) == 0);
+ assert_se(chmod(masked2e, 0755) == 0);
+ assert_se(chmod(mask2e, 0755) == 0);
if (gather_stdout)
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL);
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 29c8fd613f..6786d56197 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -30,7 +30,7 @@
#include "mkdir.h"
#include "path-util.h"
#include "rm-rf.h"
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "stat-util.h"
@@ -45,7 +45,7 @@ typedef void (*test_function_t)(Manager *m);
static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
Service *service = NULL;
usec_t ts;
- usec_t timeout = 2 * USEC_PER_SEC;
+ usec_t timeout = 2 * USEC_PER_MINUTE;
assert_se(m);
assert_se(unit);
@@ -54,7 +54,7 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected
printf("%s\n", unit->id);
exec_context_dump(&service->exec_context, stdout, "\t");
ts = now(CLOCK_MONOTONIC);
- while (service->state != SERVICE_DEAD && service->state != SERVICE_FAILED) {
+ while (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED)) {
int r;
usec_t n;
@@ -243,7 +243,7 @@ static void test_exec_inaccessiblepaths_proc(Manager *m) {
}
static void test_exec_systemcallfilter(Manager *m) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
if (!is_seccomp_available())
return;
test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
@@ -255,14 +255,14 @@ static void test_exec_systemcallfilter(Manager *m) {
}
static void test_exec_systemcallerrornumber(Manager *m) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
if (is_seccomp_available())
test(m, "exec-systemcallerrornumber.service", 1, CLD_EXITED);
#endif
}
static void test_exec_restrict_namespaces(Manager *m) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
if (!is_seccomp_available())
return;
@@ -274,7 +274,7 @@ static void test_exec_restrict_namespaces(Manager *m) {
}
static void test_exec_systemcall_system_mode_with_user(Manager *m) {
-#ifdef HAVE_SECCOMP
+#if HAVE_SECCOMP
if (!is_seccomp_available())
return;
if (getpwnam("nobody"))
@@ -317,6 +317,7 @@ static void test_exec_dynamic_user(Manager *m) {
test(m, "exec-dynamicuser-fixeduser.service", 0, CLD_EXITED);
test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", 0, CLD_EXITED);
test(m, "exec-dynamicuser-supplementarygroups.service", 0, CLD_EXITED);
+ test(m, "exec-dynamicuser-state-dir.service", 0, CLD_EXITED);
}
static void test_exec_environment(Manager *m) {
@@ -453,6 +454,10 @@ static void test_exec_read_only_path_suceed(Manager *m) {
test(m, "exec-read-only-path-succeed.service", 0, CLD_EXITED);
}
+static void test_exec_unset_environment(Manager *m) {
+ test(m, "exec-unset-environment.service", 0, CLD_EXITED);
+}
+
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
const test_function_t *test = NULL;
Manager *m = NULL;
@@ -460,7 +465,7 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) {
assert_se(tests);
- r = manager_new(scope, true, &m);
+ r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
@@ -496,7 +501,6 @@ int main(int argc, char *argv[]) {
test_exec_user,
test_exec_group,
test_exec_supplementary_groups,
- test_exec_dynamic_user,
test_exec_environment,
test_exec_environmentfile,
test_exec_passenvironment,
@@ -508,10 +512,12 @@ int main(int argc, char *argv[]) {
test_exec_ioschedulingclass,
test_exec_spec_interpolation,
test_exec_read_only_path_suceed,
+ test_exec_unset_environment,
NULL,
};
static const test_function_t system_tests[] = {
test_exec_systemcall_system_mode_with_user,
+ test_exec_dynamic_user,
NULL,
};
int r;
@@ -526,6 +532,8 @@ int main(int argc, char *argv[]) {
return EXIT_TEST_SKIP;
}
+ enter_cgroup_subroot();
+
assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
assert_se(set_unit_path(get_testdata_dir("/test-execute")) >= 0);
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index b1d688c89e..27495fa5be 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -209,7 +209,7 @@ static void test_parse_multiline_env_file(void) {
static void test_merge_env_file(void) {
char t[] = "/tmp/test-fileio-XXXXXX";
int fd, r;
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **a = NULL;
char **i;
@@ -233,7 +233,7 @@ static void test_merge_env_file(void) {
"zzz=${one:+replacement}\n"
"zzzz=${foobar:-${nothing}}\n"
"zzzzz=${nothing:+${nothing}}\n"
- , false);
+ , WRITE_STRING_FILE_AVOID_NEWLINE);
assert(r >= 0);
r = merge_env_file(&a, NULL, t);
@@ -278,7 +278,7 @@ static void test_merge_env_file(void) {
static void test_merge_env_file_invalid(void) {
char t[] = "/tmp/test-fileio-XXXXXX";
int fd, r;
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **a = NULL;
char **i;
@@ -302,7 +302,7 @@ static void test_merge_env_file_invalid(void) {
";comment2=comment2\n"
"#\n"
"\n\n" /* empty line */
- , false);
+ , WRITE_STRING_FILE_AVOID_NEWLINE);
assert(r >= 0);
r = merge_env_file(&a, NULL, t);
@@ -393,7 +393,7 @@ static void test_capeff(void) {
r = get_process_capeff(0, &capeff);
log_info("capeff: '%s' (r=%d)", capeff, r);
- if (r == -ENOENT || r == -EPERM)
+ if (IN_SET(r, -ENOENT, -EPERM))
return;
assert_se(r == 0);
@@ -414,12 +414,12 @@ static void test_write_string_stream(void) {
f = fdopen(fd, "r");
assert_se(f);
- assert_se(write_string_stream(f, "boohoo", true) < 0);
+ assert_se(write_string_stream(f, "boohoo", 0) < 0);
f = freopen(fn, "r+", f);
assert_se(f);
- assert_se(write_string_stream(f, "boohoo", true) == 0);
+ assert_se(write_string_stream(f, "boohoo", 0) == 0);
rewind(f);
assert_se(fgets(buf, sizeof(buf), f));
@@ -428,7 +428,7 @@ static void test_write_string_stream(void) {
f = freopen(fn, "w+", f);
assert_se(f);
- assert_se(write_string_stream(f, "boohoo", false) == 0);
+ assert_se(write_string_stream(f, "boohoo", WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
rewind(f);
assert_se(fgets(buf, sizeof(buf), f));
@@ -479,15 +479,15 @@ static void test_write_string_file_verify(void) {
assert_se((buf2 = strjoin(buf, "\n")));
r = write_string_file("/proc/cmdline", buf, 0);
- assert_se(r == -EACCES || r == -EIO);
+ assert_se(IN_SET(r, -EACCES, -EIO));
r = write_string_file("/proc/cmdline", buf2, 0);
- assert_se(r == -EACCES || r == -EIO);
+ assert_se(IN_SET(r, -EACCES, -EIO));
assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
- assert_se(r == -EACCES || r == -EIO);
+ assert_se(IN_SET(r, -EACCES, -EIO));
assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
}
@@ -609,9 +609,9 @@ static void test_writing_tmpfile(void) {
int fd, r;
struct iovec iov[3];
- IOVEC_SET_STRING(iov[0], "abc\n");
- IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n");
- IOVEC_SET_STRING(iov[2], "");
+ iov[0] = IOVEC_MAKE_STRING("abc\n");
+ iov[1] = IOVEC_MAKE_STRING(ALPHANUMERICAL "\n");
+ iov[2] = IOVEC_MAKE_STRING("");
fd = mkostemp_safe(name);
printf("tmpfile: %s", name);
@@ -663,6 +663,85 @@ static void test_tempfn(void) {
free(ret);
}
+static const char buffer[] =
+ "Some test data\n"
+ "With newlines, and a NUL byte\0"
+ "\n"
+ "an empty line\n"
+ "an ignored line\n"
+ "and a very long line that is supposed to be truncated, because it is so long\n";
+
+static void test_read_line_one_file(FILE *f) {
+ _cleanup_free_ char *line = NULL;
+
+ assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data"));
+ line = mfree(line);
+
+ assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
+ line = mfree(line);
+
+ assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
+ line = mfree(line);
+
+ assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
+ line = mfree(line);
+
+ assert_se(read_line(f, (size_t) -1, NULL) == 16);
+
+ assert_se(read_line(f, 16, &line) == -ENOBUFS);
+ line = mfree(line);
+
+ /* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
+ * character after the previous limit. Let's make use of tha to continue our test. */
+ assert_se(read_line(f, 1024, &line) == 61 && streq(line, "line that is supposed to be truncated, because it is so long"));
+ line = mfree(line);
+
+ assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
+ line = mfree(line);
+
+ assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
+}
+
+static void test_read_line(void) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *line = NULL;
+
+ f = fmemopen((void*) buffer, sizeof(buffer), "re");
+ assert_se(f);
+
+ test_read_line_one_file(f);
+}
+
+static void test_read_line2(void) {
+ char name[] = "/tmp/test-fileio.XXXXXX";
+ int fd;
+ _cleanup_fclose_ FILE *f = NULL;
+
+ fd = mkostemp_safe(name);
+ assert_se(fd >= 0);
+ assert_se((size_t) write(fd, buffer, sizeof(buffer)) == sizeof(buffer));
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(f = fdopen(fd, "r"));
+
+ test_read_line_one_file(f);
+}
+
+static void test_read_line3(void) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *line = NULL;
+ int r;
+
+ f = fopen("/proc/cmdline", "re");
+ if (!f && IN_SET(errno, ENOENT, EPERM))
+ return;
+ assert_se(f);
+
+ r = read_line(f, LINE_MAX, &line);
+ assert_se((size_t) r == strlen(line) + 1);
+ assert_se(read_line(f, LINE_MAX, NULL) == 0);
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
@@ -684,6 +763,9 @@ int main(int argc, char *argv[]) {
test_search_and_fopen_nulstr();
test_writing_tmpfile();
test_tempfn();
+ test_read_line();
+ test_read_line2();
+ test_read_line3();
return 0;
}
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index 1bd5c02f87..0471cd2f2f 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -18,17 +18,23 @@
***/
#include "alloc-util.h"
+#include "env-util.h"
#include "hashmap.h"
+#include "log.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
+static bool arg_slow = false;
+
void test_hashmap_funcs(void);
static void test_hashmap_replace(void) {
Hashmap *m;
char *val1, *val2, *val3, *val4, *val5, *r;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
val1 = strdup("val1");
@@ -67,6 +73,8 @@ static void test_hashmap_copy(void) {
Hashmap *m, *copy;
char *val1, *val2, *val3, *val4, *r;
+ log_info("%s", __func__);
+
val1 = strdup("val1");
assert_se(val1);
val2 = strdup("val2");
@@ -103,6 +111,8 @@ static void test_hashmap_get_strv(void) {
char **strv;
char *val1, *val2, *val3, *val4;
+ log_info("%s", __func__);
+
val1 = strdup("val1");
assert_se(val1);
val2 = strdup("val2");
@@ -139,6 +149,8 @@ static void test_hashmap_move_one(void) {
Hashmap *m, *n;
char *val1, *val2, *val3, *val4, *r;
+ log_info("%s", __func__);
+
val1 = strdup("val1");
assert_se(val1);
val2 = strdup("val2");
@@ -178,6 +190,8 @@ static void test_hashmap_move(void) {
Hashmap *m, *n;
char *val1, *val2, *val3, *val4, *r;
+ log_info("%s", __func__);
+
val1 = strdup("val1");
assert_se(val1);
val2 = strdup("val2");
@@ -220,6 +234,8 @@ static void test_hashmap_update(void) {
Hashmap *m;
char *val1, *val2, *r;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
val1 = strdup("old_value");
assert_se(val1);
@@ -250,6 +266,8 @@ static void test_hashmap_put(void) {
void *val2 = (void*) "val 2";
_cleanup_free_ char* key1 = NULL;
+ log_info("%s", __func__);
+
assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0);
assert_se(m);
@@ -268,6 +286,8 @@ static void test_hashmap_remove(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
char *r;
+ log_info("%s", __func__);
+
r = hashmap_remove(NULL, "key 1");
assert_se(r == NULL);
@@ -296,6 +316,8 @@ static void test_hashmap_remove2(void) {
char val2[] = "val 2";
void *r, *r2;
+ log_info("%s", __func__);
+
r = hashmap_remove2(NULL, "key 1", &r2);
assert_se(r == NULL);
@@ -326,6 +348,8 @@ static void test_hashmap_remove_value(void) {
char val1[] = "val 1";
char val2[] = "val 2";
+ log_info("%s", __func__);
+
r = hashmap_remove_value(NULL, "key 1", val1);
assert_se(r == NULL);
@@ -358,6 +382,8 @@ static void test_hashmap_remove_and_put(void) {
int valid;
char *r;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -392,6 +418,8 @@ static void test_hashmap_remove_and_replace(void) {
void *r;
int i, j;
+ log_info("%s", __func__);
+
m = hashmap_new(&trivial_hash_ops);
assert_se(m);
@@ -443,6 +471,8 @@ static void test_hashmap_ensure_allocated(void) {
Hashmap *m;
int valid_hashmap;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
valid_hashmap = hashmap_ensure_allocated(&m, &string_hash_ops);
@@ -464,6 +494,8 @@ static void test_hashmap_foreach_key(void) {
"key 3\0"
"key 4\0";
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
NULSTR_FOREACH(key, key_table)
@@ -494,6 +526,8 @@ static void test_hashmap_foreach(void) {
char *val1, *val2, *val3, *val4, *s;
unsigned count;
+ log_info("%s", __func__);
+
val1 = strdup("my val1");
assert_se(val1);
val2 = strdup("my val2");
@@ -544,6 +578,8 @@ static void test_hashmap_merge(void) {
Hashmap *n;
char *val1, *val2, *val3, *val4, *r;
+ log_info("%s", __func__);
+
val1 = strdup("my val1");
assert_se(val1);
val2 = strdup("my val2");
@@ -577,6 +613,8 @@ static void test_hashmap_contains(void) {
Hashmap *m;
char *val1;
+ log_info("%s", __func__);
+
val1 = strdup("my val");
assert_se(val1);
@@ -597,6 +635,8 @@ static void test_hashmap_isempty(void) {
Hashmap *m;
char *val1;
+ log_info("%s", __func__);
+
val1 = strdup("my val");
assert_se(val1);
@@ -614,6 +654,8 @@ static void test_hashmap_size(void) {
Hashmap *m;
char *val1, *val2, *val3, *val4;
+ log_info("%s", __func__);
+
val1 = strdup("my val");
assert_se(val1);
val2 = strdup("my val");
@@ -644,6 +686,8 @@ static void test_hashmap_get(void) {
char *r;
char *val;
+ log_info("%s", __func__);
+
val = strdup("my val");
assert_se(val);
@@ -671,6 +715,8 @@ static void test_hashmap_get2(void) {
char key_orig[] = "Key 1";
void *key_copy;
+ log_info("%s", __func__);
+
val = strdup("my val");
assert_se(val);
@@ -710,14 +756,15 @@ static void test_hashmap_many(void) {
Hashmap *h;
unsigned i, j;
void *v, *k;
- static const struct {
+ const struct {
const struct hash_ops *ops;
unsigned n_entries;
} tests[] = {
- { .ops = NULL, .n_entries = 1 << 20 },
- { .ops = &crippled_hashmap_ops, .n_entries = 1 << 14 },
+ { .ops = NULL, .n_entries = arg_slow ? 1 << 20 : 240 },
+ { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 },
};
+ log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast");
for (j = 0; j < ELEMENTSOF(tests); j++) {
assert_se(h = hashmap_new(tests[j].ops));
@@ -748,6 +795,8 @@ static void test_hashmap_many(void) {
static void test_hashmap_first(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -765,6 +814,8 @@ static void test_hashmap_first(void) {
static void test_hashmap_first_key(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -782,6 +833,8 @@ static void test_hashmap_first_key(void) {
static void test_hashmap_steal_first_key(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -797,6 +850,8 @@ static void test_hashmap_steal_first(void) {
int seen[3] = {};
char *val;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -815,6 +870,8 @@ static void test_hashmap_steal_first(void) {
static void test_hashmap_clear_free_free(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(m);
@@ -829,6 +886,8 @@ static void test_hashmap_clear_free_free(void) {
static void test_hashmap_reserve(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
+ log_info("%s", __func__);
+
m = hashmap_new(&string_hash_ops);
assert_se(hashmap_reserve(m, 1) == 0);
@@ -844,6 +903,14 @@ static void test_hashmap_reserve(void) {
}
void test_hashmap_funcs(void) {
+ int r;
+
+ log_parse_environment();
+ log_open();
+
+ r = getenv_bool("SYSTEMD_SLOW_TESTS");
+ arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
+
test_hashmap_copy();
test_hashmap_get_strv();
test_hashmap_move_one();
diff --git a/src/test/test-helper.c b/src/test/test-helper.c
new file mode 100644
index 0000000000..5b707c3276
--- /dev/null
+++ b/src/test/test-helper.c
@@ -0,0 +1,41 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 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 "test-helper.h"
+#include "random-util.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+
+void enter_cgroup_subroot(void) {
+ _cleanup_free_ char *cgroup_root = NULL, *cgroup_subroot = NULL;
+ CGroupMask supported;
+
+ assert_se(cg_pid_get_path(NULL, 0, &cgroup_root) >= 0);
+ assert_se(asprintf(&cgroup_subroot, "%s/%" PRIx64, cgroup_root, random_u64()) >= 0);
+ assert_se(cg_mask_supported(&supported) >= 0);
+
+ /* If this fails, then we don't mind as the later cgroup operations will fail too, and it's fine if we handle
+ * any errors at that point. */
+
+ if (cg_create_everywhere(supported, _CGROUP_MASK_ALL, cgroup_subroot) < 0)
+ return;
+
+ if (cg_attach_everywhere(supported, cgroup_subroot, 0, NULL, NULL) < 0)
+ return;
+}
diff --git a/src/test/test-helper.h b/src/test/test-helper.h
index ddb10f88fd..8af32c8744 100644
--- a/src/test/test-helper.h
+++ b/src/test/test-helper.h
@@ -39,3 +39,5 @@
-ENOENT, \
-ENOMEDIUM /* cannot determine cgroup */ \
)
+
+void enter_cgroup_subroot(void);
diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c
new file mode 100644
index 0000000000..8b7a1229fe
--- /dev/null
+++ b/src/test/test-in-addr-util.c
@@ -0,0 +1,75 @@
+/***
+ This file is part of systemd
+
+ Copyright 2017 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 <netinet/in.h>
+
+#include "in-addr-util.h"
+
+static void test_in_addr_prefix_from_string(const char *p, int family, int ret, const union in_addr_union *u, unsigned char prefixlen) {
+ union in_addr_union q;
+ unsigned char l;
+ int r;
+
+ r = in_addr_prefix_from_string(p, family, &q, &l);
+ assert_se(r == ret);
+
+ if (r >= 0) {
+ int f;
+
+ assert_se(in_addr_equal(family, &q, u));
+ assert_se(l == prefixlen);
+
+ r = in_addr_prefix_from_string_auto(p, &f, &q, &l);
+ assert_se(r >= 0);
+
+ assert_se(f == family);
+ assert_se(in_addr_equal(family, &q, u));
+ assert_se(l == prefixlen);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32);
+ test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0);
+ test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1);
+ test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2);
+ test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32);
+ test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0);
+ test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0);
+ test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0);
+
+ test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0);
+ test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128);
+ test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0);
+ test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1);
+ test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2);
+ test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32);
+ test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33);
+ test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64);
+ test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128);
+ test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0);
+ test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0);
+
+ return 0;
+}
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
index 575401cb91..e2754a0773 100644
--- a/src/test/test-install-root.c
+++ b/src/test/test-install-root.c
@@ -381,6 +381,8 @@ static void test_template_enable(const char *root) {
UnitFileState state;
const char *p;
+ log_info("== %s ==", __func__);
+
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT);
@@ -402,6 +404,8 @@ static void test_template_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ log_info("== %s with template@.service enabled ==", __func__);
+
assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
assert_se(n_changes == 1);
assert_se(changes[0].type == UNIT_FILE_SYMLINK);
@@ -432,6 +436,8 @@ static void test_template_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ log_info("== %s with template@foo.service enabled ==", __func__);
+
assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
assert_se(changes[0].type == UNIT_FILE_SYMLINK);
assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
@@ -440,7 +446,7 @@ static void test_template_enable(const char *root) {
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
@@ -463,6 +469,8 @@ static void test_template_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ log_info("== %s with template-symlink@quux.service enabled ==", __func__);
+
assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0);
assert_se(changes[0].type == UNIT_FILE_SYMLINK);
assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
@@ -471,11 +479,11 @@ static void test_template_enable(const char *root) {
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
- assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
diff --git a/src/test/test-log.c b/src/test/test-log.c
index 626d2c6135..8ab569f477 100644
--- a/src/test/test-log.c
+++ b/src/test/test-log.c
@@ -39,7 +39,7 @@ int main(int argc, char* argv[]) {
log_open();
log_struct(LOG_INFO,
- "MESSAGE=Waldo PID="PID_FMT, getpid(),
+ "MESSAGE=Waldo PID="PID_FMT, getpid_cached(),
"SERVICE=piepapo",
NULL);
@@ -47,12 +47,12 @@ int main(int argc, char* argv[]) {
log_open();
log_struct(LOG_INFO,
- "MESSAGE=Foobar PID="PID_FMT, getpid(),
+ "MESSAGE=Foobar PID="PID_FMT, getpid_cached(),
"SERVICE=foobar",
NULL);
log_struct(LOG_INFO,
- "MESSAGE=Foobar PID="PID_FMT, getpid(),
+ "MESSAGE=Foobar PID="PID_FMT, getpid_cached(),
"FORMAT_STR_TEST=1=%i A=%c 2=%hi 3=%li 4=%lli 1=%p foo=%s 2.5=%g 3.5=%g 4.5=%Lg",
(int) 1, 'A', (short) 2, (long int) 3, (long long int) 4, (void*) 1, "foo", (float) 2.5f, (double) 3.5, (long double) 4.5,
"SUFFIX=GOT IT",
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 0125d905a6..b142c3a115 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -82,6 +82,7 @@ int main(int argc, char *argv[]) {
(char **) writable,
(char **) readonly,
(char **) inaccessible,
+ NULL,
&(BindMount) { .source = (char*) "/usr/bin", .destination = (char*) "/etc/systemd", .read_only = true }, 1,
tmp_dir,
var_tmp_dir,
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
index 57eeb8e40c..9f73bc9a5d 100644
--- a/src/test/test-nss.c
+++ b/src/test/test-nss.c
@@ -97,7 +97,7 @@ static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
memcpy(&u, it->addr, 16);
r = in_addr_to_string(it->family, &u, &a);
- assert_se(r == 0 || r == -EAFNOSUPPORT);
+ assert_se(IN_SET(r, 0, -EAFNOSUPPORT));
if (r == -EAFNOSUPPORT)
assert_se((a = hexmem(it->addr, 16)));
@@ -450,13 +450,13 @@ static int parse_argv(int argc, char **argv,
modules = strv_new(argv[1], NULL);
else
modules = strv_new(
-#ifdef HAVE_MYHOSTNAME
+#if ENABLE_MYHOSTNAME
"myhostname",
#endif
-#ifdef HAVE_RESOLVED
+#if ENABLE_RESOLVE
"resolve",
#endif
-#ifdef HAVE_MACHINED
+#if ENABLE_MACHINED
"mymachines",
#endif
"dns",
@@ -491,7 +491,7 @@ static int parse_argv(int argc, char **argv,
if (!hostname)
return -ENOMEM;
- names = strv_new("localhost", "gateway", "foo_no_such_host", hostname, NULL);
+ names = strv_new("localhost", "_gateway", "foo_no_such_host", hostname, NULL);
if (!names)
return -ENOMEM;
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index e5644246c2..ff46a896b5 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -261,6 +261,7 @@ static void test_make_relative(void) {
assert_se(path_make_relative("some/relative/path", "/some/path", &result) < 0);
assert_se(path_make_relative("/some/path", "some/relative/path", &result) < 0);
+ assert_se(path_make_relative("/some/dotdot/../path", "/some/path", &result) < 0);
#define test(from_dir, to_path, expected) { \
_cleanup_free_ char *z = NULL; \
@@ -274,6 +275,7 @@ static void test_make_relative(void) {
test("/some/path", "/some/path/in/subdir", "in/subdir");
test("/some/path", "/", "../..");
test("/some/path", "/some/other/path", "../other/path");
+ test("/some/path/./dot", "/some/further/path", "../../further/path");
test("//extra/////slashes///won't////fool///anybody//", "////extra///slashes////are/just///fine///", "../../../are/just/fine");
}
@@ -588,6 +590,21 @@ static void test_systemd_installation_has_version(const char *path) {
}
}
+static void test_skip_dev_prefix(void) {
+
+ assert_se(streq(skip_dev_prefix("/"), "/"));
+ assert_se(streq(skip_dev_prefix("/dev"), ""));
+ assert_se(streq(skip_dev_prefix("/dev/"), ""));
+ assert_se(streq(skip_dev_prefix("/dev/foo"), "foo"));
+ assert_se(streq(skip_dev_prefix("/dev/foo/bar"), "foo/bar"));
+ assert_se(streq(skip_dev_prefix("//dev"), ""));
+ assert_se(streq(skip_dev_prefix("//dev//"), ""));
+ assert_se(streq(skip_dev_prefix("/dev///foo"), "foo"));
+ assert_se(streq(skip_dev_prefix("///dev///foo///bar"), "foo///bar"));
+ assert_se(streq(skip_dev_prefix("//foo"), "//foo"));
+ assert_se(streq(skip_dev_prefix("foo"), "foo"));
+}
+
int main(int argc, char **argv) {
log_set_max_level(LOG_DEBUG);
log_parse_environment();
@@ -607,6 +624,7 @@ int main(int argc, char **argv) {
test_file_in_same_dir();
test_filename_is_valid();
test_hidden_or_backup_file();
+ test_skip_dev_prefix();
test_systemd_installation_has_version(argv[1]); /* NULL is OK */
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 70ac6b3df3..c1915017df 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -45,7 +45,9 @@ static int setup_test(Manager **m) {
assert_se(m);
- r = manager_new(UNIT_FILE_USER, true, &tmp);
+ enter_cgroup_subroot();
+
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &tmp);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return -EXIT_TEST_SKIP;
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index c5edbcc5d2..0f0e2cbcb9 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -26,7 +26,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
@@ -115,7 +115,7 @@ static void test_pid_is_unwaited(void) {
waitpid(pid, &status, 0);
assert_se(!pid_is_unwaited(pid));
}
- assert_se(pid_is_unwaited(getpid()));
+ assert_se(pid_is_unwaited(getpid_cached()));
assert_se(!pid_is_unwaited(-1));
}
@@ -132,7 +132,7 @@ static void test_pid_is_alive(void) {
waitpid(pid, &status, 0);
assert_se(!pid_is_alive(pid));
}
- assert_se(pid_is_alive(getpid()));
+ assert_se(pid_is_alive(getpid_cached()));
assert_se(!pid_is_alive(-1));
}
@@ -168,7 +168,7 @@ static void test_get_process_cmdline_harder(void) {
if (geteuid() != 0)
return;
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
/* valgrind patches open(/proc//cmdline)
* so, test_get_process_cmdline_harder fails always
* See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */
@@ -205,149 +205,149 @@ static void test_get_process_cmdline_harder(void) {
assert_se(prctl(PR_SET_NAME, "testa") >= 0);
- assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
+ assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
- assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
assert_se(streq(line, ""));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
assert_se(streq(line, "["));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
assert_se(streq(line, "[."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
assert_se(streq(line, "[.."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
assert_se(streq(line, "[..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
assert_se(streq(line, "[...]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
assert_se(streq(line, "[t...]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10);
- assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
+ assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
- assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
assert_se(streq(line, "[testa]"));
line = mfree(line);
assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10);
- assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
assert_se(streq(line, "foo bar"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
assert_se(streq(line, "foo bar"));
line = mfree(line);
assert_se(write(fd, "quux", 4) == 4);
- assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 1, true, &line) >= 0);
assert_se(streq(line, ""));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 2, true, &line) >= 0);
assert_se(streq(line, "."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 3, true, &line) >= 0);
assert_se(streq(line, ".."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 4, true, &line) >= 0);
assert_se(streq(line, "..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 5, true, &line) >= 0);
assert_se(streq(line, "f..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 6, true, &line) >= 0);
assert_se(streq(line, "fo..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 7, true, &line) >= 0);
assert_se(streq(line, "foo..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 8, true, &line) >= 0);
assert_se(streq(line, "foo..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 9, true, &line) >= 0);
assert_se(streq(line, "foo b..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
assert_se(streq(line, "foo ba..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
assert_se(streq(line, "foo bar..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
assert_se(streq(line, "foo bar..."));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 13, true, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 14, true, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 1000, true, &line) >= 0);
assert_se(streq(line, "foo bar quux"));
line = mfree(line);
assert_se(ftruncate(fd, 0) >= 0);
assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
- assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT);
+ assert_se(get_process_cmdline(getpid_cached(), 0, false, &line) == -ENOENT);
- assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 0, true, &line) >= 0);
assert_se(streq(line, "[aaaa bbbb cccc]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 10, true, &line) >= 0);
assert_se(streq(line, "[aaaa...]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 11, true, &line) >= 0);
assert_se(streq(line, "[aaaa...]"));
line = mfree(line);
- assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0);
+ assert_se(get_process_cmdline(getpid_cached(), 12, true, &line) >= 0);
assert_se(streq(line, "[aaaa b...]"));
line = mfree(line);
@@ -355,38 +355,22 @@ static void test_get_process_cmdline_harder(void) {
_exit(0);
}
-static void test_rename_process_one(const char *p, int ret) {
+static void test_rename_process_now(const char *p, int ret) {
_cleanup_free_ char *comm = NULL, *cmdline = NULL;
- pid_t pid;
int r;
- pid = fork();
- assert_se(pid >= 0);
-
- if (pid > 0) {
- siginfo_t si;
-
- assert_se(wait_for_terminate(pid, &si) >= 0);
- assert_se(si.si_code == CLD_EXITED);
- assert_se(si.si_status == EXIT_SUCCESS);
-
- return;
- }
-
- /* child */
r = rename_process(p);
-
assert_se(r == ret ||
(ret == 0 && r >= 0) ||
(ret > 0 && r > 0));
if (r < 0)
- goto finish;
+ return;
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
/* see above, valgrind is weird, we can't verify what we are doing here */
if (RUNNING_ON_VALGRIND)
- goto finish;
+ return;
#endif
assert_se(get_process_comm(0, &comm) >= 0);
@@ -394,11 +378,57 @@ static void test_rename_process_one(const char *p, int ret) {
assert_se(strneq(comm, p, 15));
assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0);
- log_info("cmdline = <%s>", cmdline);
- assert_se(strneq(p, cmdline, strlen("test-process-util")));
- assert_se(startswith(p, cmdline));
+ /* we cannot expect cmdline to be renamed properly without privileges */
+ if (geteuid() == 0) {
+ log_info("cmdline = <%s>", cmdline);
+ assert_se(strneq(p, cmdline, strlen("test-process-util")));
+ assert_se(startswith(p, cmdline));
+ } else
+ log_info("cmdline = <%s> (not verified)", cmdline);
+}
+
+static void test_rename_process_one(const char *p, int ret) {
+ siginfo_t si;
+ pid_t pid;
+
+ pid = fork();
+ assert_se(pid >= 0);
+
+ if (pid == 0) {
+ /* child */
+ test_rename_process_now(p, ret);
+ _exit(EXIT_SUCCESS);
+ }
+
+ assert_se(wait_for_terminate(pid, &si) >= 0);
+ assert_se(si.si_code == CLD_EXITED);
+ assert_se(si.si_status == EXIT_SUCCESS);
+}
+
+static void test_rename_process_multi(void) {
+ pid_t pid;
-finish:
+ pid = fork();
+ assert_se(pid >= 0);
+
+ if (pid > 0) {
+ siginfo_t si;
+
+ assert_se(wait_for_terminate(pid, &si) >= 0);
+ assert_se(si.si_code == CLD_EXITED);
+ assert_se(si.si_status == EXIT_SUCCESS);
+
+ return;
+ }
+
+ /* child */
+ test_rename_process_now("one", 1);
+ test_rename_process_now("more", 0); /* longer than "one", hence truncated */
+ setresuid(99, 99, 99);
+ test_rename_process_now("time!", 0);
+ test_rename_process_now("0", 1); /* shorter than "one", should fit */
+ test_rename_process_one("", -EINVAL);
+ test_rename_process_one(NULL, -EINVAL);
_exit(EXIT_SUCCESS);
}
@@ -408,6 +438,62 @@ static void test_rename_process(void) {
test_rename_process_one("foo", 1); /* should always fit */
test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */
test_rename_process_one("1234567", 1); /* should always fit */
+ test_rename_process_multi(); /* multiple invocations and dropped privileges */
+}
+
+static void test_getpid_cached(void) {
+ siginfo_t si;
+ pid_t a, b, c, d, e, f, child;
+
+ a = raw_getpid();
+ b = getpid_cached();
+ c = getpid();
+
+ assert_se(a == b && a == c);
+
+ child = fork();
+ assert_se(child >= 0);
+
+ if (child == 0) {
+ /* In child */
+ a = raw_getpid();
+ b = getpid_cached();
+ c = getpid();
+
+ assert_se(a == b && a == c);
+ _exit(0);
+ }
+
+ d = raw_getpid();
+ e = getpid_cached();
+ f = getpid();
+
+ assert_se(a == d && a == e && a == f);
+
+ assert_se(wait_for_terminate(child, &si) >= 0);
+ assert_se(si.si_status == 0);
+ assert_se(si.si_code == CLD_EXITED);
+}
+
+#define MEASURE_ITERATIONS (10000000LLU)
+
+static void test_getpid_measure(void) {
+ unsigned long long i;
+ usec_t t, q;
+
+ t = now(CLOCK_MONOTONIC);
+ for (i = 0; i < MEASURE_ITERATIONS; i++)
+ (void) getpid();
+ q = now(CLOCK_MONOTONIC) - t;
+
+ log_info(" glibc getpid(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
+
+ t = now(CLOCK_MONOTONIC);
+ for (i = 0; i < MEASURE_ITERATIONS; i++)
+ (void) getpid_cached();
+ q = now(CLOCK_MONOTONIC) - t;
+
+ log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
}
int main(int argc, char *argv[]) {
@@ -434,6 +520,8 @@ int main(int argc, char *argv[]) {
test_personality();
test_get_process_cmdline_harder();
test_rename_process();
+ test_getpid_cached();
+ test_getpid_measure();
return 0;
}
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index 81d9abc2d5..9bed4b3832 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -34,10 +34,12 @@ int main(int argc, char *argv[]) {
FDSet *fdset = NULL;
int r;
+ enter_cgroup_subroot();
+
/* prepare the test */
assert_se(set_unit_path(get_testdata_dir("")) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
- r = manager_new(UNIT_FILE_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
index efd145e063..4d63b68809 100644
--- a/src/test/test-seccomp.c
+++ b/src/test/test-seccomp.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
+#include <sys/personality.h>
#include <sys/poll.h>
#include <sys/shm.h>
#include <sys/types.h>
@@ -47,7 +48,6 @@
# define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0
#endif
-
static void test_seccomp_arch_to_string(void) {
uint32_t a, b;
const char *name;
@@ -244,13 +244,17 @@ static void test_protect_sysctl(void) {
assert_se(pid >= 0);
if (pid == 0) {
+#if __NR__sysctl > 0
assert_se(syscall(__NR__sysctl, NULL) < 0);
assert_se(errno == EFAULT);
+#endif
assert_se(seccomp_protect_sysctl() >= 0);
+#if __NR__sysctl > 0
assert_se(syscall(__NR__sysctl, 0, 0, 0) < 0);
assert_se(errno == EPERM);
+#endif
_exit(EXIT_SUCCESS);
}
@@ -525,7 +529,11 @@ static void test_load_syscall_filter_set_raw(void) {
assert_se(poll(NULL, 0, 0) == 0);
assert_se(s = set_new(NULL));
+#if SCMP_SYS(access) >= 0
assert_se(set_put(s, UINT32_TO_PTR(__NR_access + 1)) >= 0);
+#else
+ assert_se(set_put(s, UINT32_TO_PTR(__NR_faccessat + 1)) >= 0);
+#endif
assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUCLEAN)) >= 0);
@@ -537,7 +545,11 @@ static void test_load_syscall_filter_set_raw(void) {
s = set_free(s);
assert_se(s = set_new(NULL));
+#if SCMP_SYS(poll) >= 0
assert_se(set_put(s, UINT32_TO_PTR(__NR_poll + 1)) >= 0);
+#else
+ assert_se(set_put(s, UINT32_TO_PTR(__NR_ppoll + 1)) >= 0);
+#endif
assert_se(seccomp_load_syscall_filter_set_raw(SCMP_ACT_ALLOW, s, SCMP_ACT_ERRNO(EUNATCH)) >= 0);
@@ -553,6 +565,83 @@ static void test_load_syscall_filter_set_raw(void) {
assert_se(wait_for_terminate_and_warn("syscallrawseccomp", pid, true) == EXIT_SUCCESS);
}
+static void test_lock_personality(void) {
+ unsigned long current;
+ pid_t pid;
+
+ if (!is_seccomp_available())
+ return;
+ if (geteuid() != 0)
+ return;
+
+ assert_se(opinionated_personality(&current) >= 0);
+
+ log_info("current personality=%lu", current);
+
+ pid = fork();
+ assert_se(pid >= 0);
+
+ if (pid == 0) {
+ assert_se(seccomp_lock_personality(current) >= 0);
+
+ assert_se((unsigned long) safe_personality(current) == current);
+
+ /* Note, we also test that safe_personality() works correctly, by checkig whether errno is properly
+ * set, in addition to the return value */
+ errno = 0;
+ assert_se(safe_personality(PER_LINUX | ADDR_NO_RANDOMIZE) == -EPERM);
+ assert_se(errno == EPERM);
+
+ assert_se(safe_personality(PER_LINUX | MMAP_PAGE_ZERO) == -EPERM);
+ assert_se(safe_personality(PER_LINUX | ADDR_COMPAT_LAYOUT) == -EPERM);
+ assert_se(safe_personality(PER_LINUX | READ_IMPLIES_EXEC) == -EPERM);
+ assert_se(safe_personality(PER_LINUX_32BIT) == -EPERM);
+ assert_se(safe_personality(PER_SVR4) == -EPERM);
+ assert_se(safe_personality(PER_BSD) == -EPERM);
+ assert_se(safe_personality(current == PER_LINUX ? PER_LINUX32 : PER_LINUX) == -EPERM);
+ assert_se(safe_personality(PER_LINUX32_3GB) == -EPERM);
+ assert_se(safe_personality(PER_UW7) == -EPERM);
+ assert_se(safe_personality(0x42) == -EPERM);
+
+ assert_se(safe_personality(PERSONALITY_INVALID) == -EPERM); /* maybe remove this later */
+
+ assert_se((unsigned long) personality(current) == current);
+ _exit(EXIT_SUCCESS);
+ }
+
+ assert_se(wait_for_terminate_and_warn("lockpersonalityseccomp", pid, true) == EXIT_SUCCESS);
+}
+
+static void test_filter_sets_ordered(void) {
+ size_t i;
+
+ /* Ensure "@default" always remains at the beginning of the list */
+ assert_se(SYSCALL_FILTER_SET_DEFAULT == 0);
+ assert_se(streq(syscall_filter_sets[0].name, "@default"));
+
+ for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
+ const char *k, *p = NULL;
+
+ /* Make sure each group has a description */
+ assert_se(!isempty(syscall_filter_sets[0].help));
+
+ /* Make sure the groups are ordered alphabetically, except for the first entry */
+ assert_se(i < 2 || strcmp(syscall_filter_sets[i-1].name, syscall_filter_sets[i].name) < 0);
+
+ NULSTR_FOREACH(k, syscall_filter_sets[i].value) {
+
+ /* Ensure each syscall list is in itself ordered, but groups before names */
+ assert_se(!p ||
+ (*p == '@' && *k != '@') ||
+ (((*p == '@' && *k == '@') ||
+ (*p != '@' && *k != '@')) &&
+ strcmp(p, k) < 0));
+
+ p = k;
+ }
+ }
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
@@ -569,6 +658,8 @@ int main(int argc, char *argv[]) {
test_memory_deny_write_execute_shmat();
test_restrict_archs();
test_load_syscall_filter_set_raw();
+ test_lock_personality();
+ test_filter_sets_ordered();
return 0;
}
diff --git a/src/test/test-set.c b/src/test/test-set.c
index 0ee5ddcc9f..3fab350cf6 100644
--- a/src/test/test-set.c
+++ b/src/test/test-set.c
@@ -55,9 +55,54 @@ static void test_set_put(void) {
assert_se(set_put(m, (void*) "22") == 0);
}
+static void test_set_make(void) {
+ _cleanup_set_free_ Set *s = NULL;
+
+ assert_se(set_make(&s, NULL, UINT_TO_PTR(4), UINT_TO_PTR(6), UINT_TO_PTR(8), NULL) == 0);
+ assert_se(set_size(s) == 3);
+ assert_se(!set_contains(s, UINT_TO_PTR(0)));
+ assert_se(!set_contains(s, UINT_TO_PTR(1)));
+ assert_se(!set_contains(s, UINT_TO_PTR(2)));
+ assert_se(!set_contains(s, UINT_TO_PTR(3)));
+ assert_se(set_contains(s, UINT_TO_PTR(4)));
+ assert_se(!set_contains(s, UINT_TO_PTR(5)));
+ assert_se(set_contains(s, UINT_TO_PTR(6)));
+ assert_se(!set_contains(s, UINT_TO_PTR(7)));
+ assert_se(set_contains(s, UINT_TO_PTR(8)));
+ assert_se(!set_contains(s, UINT_TO_PTR(9)));
+ s = set_free(s);
+
+ assert_se(set_make(&s, NULL, NULL) == 0);
+ assert_se(set_size(s) == 0);
+ assert_se(!set_contains(s, UINT_TO_PTR(0)));
+ assert_se(!set_contains(s, UINT_TO_PTR(4)));
+ assert_se(!set_contains(s, UINT_TO_PTR(6)));
+ assert_se(!set_contains(s, UINT_TO_PTR(8)));
+ s = set_free(s);
+
+ assert_se(set_make(&s, NULL, UINT_TO_PTR(3), NULL) == 0);
+ assert_se(set_size(s) == 1);
+ assert_se(!set_contains(s, UINT_TO_PTR(0)));
+ assert_se(!set_contains(s, UINT_TO_PTR(1)));
+ assert_se(!set_contains(s, UINT_TO_PTR(2)));
+ assert_se(set_contains(s, UINT_TO_PTR(3)));
+ assert_se(!set_contains(s, UINT_TO_PTR(4)));
+
+ assert_se(set_make(&s, NULL, UINT_TO_PTR(2), UINT_TO_PTR(5), NULL) == 0);
+ assert_se(set_size(s) == 2);
+ assert_se(!set_contains(s, UINT_TO_PTR(0)));
+ assert_se(!set_contains(s, UINT_TO_PTR(1)));
+ assert_se(set_contains(s, UINT_TO_PTR(2)));
+ assert_se(!set_contains(s, UINT_TO_PTR(3)));
+ assert_se(!set_contains(s, UINT_TO_PTR(4)));
+ assert_se(set_contains(s, UINT_TO_PTR(5)));
+ assert_se(!set_contains(s, UINT_TO_PTR(6)));
+}
+
int main(int argc, const char *argv[]) {
test_set_steal_first();
test_set_put();
+ test_set_make();
return 0;
}
diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c
index 7a4a8a6636..bcc08b226c 100644
--- a/src/test/test-sigbus.c
+++ b/src/test/test-sigbus.c
@@ -22,7 +22,7 @@
#include "fd-util.h"
#include "sigbus.h"
#include "util.h"
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
#include <valgrind/valgrind.h>
#endif
@@ -32,7 +32,7 @@ int main(int argc, char *argv[]) {
void *addr = NULL;
uint8_t *p;
-#ifdef HAVE_VALGRIND_VALGRIND_H
+#if HAVE_VALGRIND_VALGRIND_H
if (RUNNING_ON_VALGRIND)
return EXIT_TEST_SKIP;
#endif
diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c
index 671eb869cb..92e3927784 100644
--- a/src/test/test-signal-util.c
+++ b/src/test/test-signal-util.c
@@ -50,12 +50,12 @@ static void test_block_signals(void) {
static void test_ignore_signals(void) {
assert_se(ignore_signals(SIGINT, -1) >= 0);
- assert_se(kill(getpid(), SIGINT) >= 0);
+ assert_se(kill(getpid_cached(), SIGINT) >= 0);
assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
- assert_se(kill(getpid(), SIGUSR1) >= 0);
- assert_se(kill(getpid(), SIGUSR2) >= 0);
- assert_se(kill(getpid(), SIGTERM) >= 0);
- assert_se(kill(getpid(), SIGPIPE) >= 0);
+ assert_se(kill(getpid_cached(), SIGUSR1) >= 0);
+ assert_se(kill(getpid_cached(), SIGUSR2) >= 0);
+ assert_se(kill(getpid_cached(), SIGTERM) >= 0);
+ assert_se(kill(getpid_cached(), SIGPIPE) >= 0);
assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
}
diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c
index 269adfd18f..bfc421e4ba 100644
--- a/src/test/test-sizeof.c
+++ b/src/test/test-sizeof.c
@@ -60,6 +60,8 @@ int main(void) {
info(time_t);
info(usec_t);
info(__time_t);
+ info(pid_t);
+ info(gid_t);
info(enum Enum);
info(enum BigEnum);
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
index 4b3e924cfb..604701ff7a 100644
--- a/src/test/test-string-util.c
+++ b/src/test/test-string-util.c
@@ -336,6 +336,12 @@ static void test_first_word(void) {
assert_se(!first_word("Hellooo", "Hello"));
}
+static void test_strlen_ptr(void) {
+ assert_se(strlen_ptr("foo") == 3);
+ assert_se(strlen_ptr("") == 0);
+ assert_se(strlen_ptr(NULL) == 0);
+}
+
int main(int argc, char *argv[]) {
test_string_erase();
test_ascii_strcasecmp_n();
@@ -358,6 +364,7 @@ int main(int argc, char *argv[]) {
test_in_charset();
test_split_pair();
test_first_word();
+ test_strlen_ptr();
return 0;
}
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 294d219869..a16b04dbd2 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -19,7 +19,6 @@
#include "architecture.h"
#include "automount.h"
-#include "busname.h"
#include "cgroup.h"
#include "compress.h"
#include "condition.h"
@@ -54,9 +53,6 @@ int main(int argc, char **argv) {
test_table(architecture, ARCHITECTURE);
test_table(automount_result, AUTOMOUNT_RESULT);
test_table(automount_state, AUTOMOUNT_STATE);
- test_table(bus_policy_access, BUS_POLICY_ACCESS);
- test_table(busname_result, BUSNAME_RESULT);
- test_table(busname_state, BUSNAME_STATE);
test_table(cgroup_device_policy, CGROUP_DEVICE_POLICY);
test_table(condition_type, CONDITION_TYPE);
test_table(assert_type, CONDITION_TYPE);
diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c
index a7c86d155a..b4c76048a4 100644
--- a/src/test/test-tmpfiles.c
+++ b/src/test/test-tmpfiles.c
@@ -45,7 +45,7 @@ int main(int argc, char** argv) {
fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
assert_se(fd >= 0);
- assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
+ assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd) > 0);
(void) system(cmd);
assert_se(readlink_malloc(cmd + 6, &ans) >= 0);
log_debug("link1: %s", ans);
@@ -55,7 +55,7 @@ int main(int argc, char** argv) {
assert_se(fd >= 0);
assert_se(unlink(pattern) == 0);
- assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0);
+ assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd2) > 0);
(void) system(cmd2);
assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0);
log_debug("link2: %s", ans2);
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index fd797b587e..07f21d0d3d 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -55,7 +55,7 @@ static int test_unit_file_get_set(void) {
r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
- if (r == -EPERM || r == -EACCES) {
+ if (IN_SET(r, -EPERM, -EACCES)) {
log_notice_errno(r, "Skipping test: unit_file_get_list: %m");
return EXIT_TEST_SKIP;
}
@@ -93,7 +93,7 @@ static void check_execcommand(ExecCommand *c,
assert_se(streq_ptr(c->argv[1], argv1));
if (n > 1)
assert_se(streq_ptr(c->argv[2], argv2));
- assert_se(c->ignore == ignore);
+ assert_se(!!(c->flags & EXEC_COMMAND_IGNORE_FAILURE) == ignore);
}
static void test_config_parse_exec(void) {
@@ -115,7 +115,7 @@ static void test_config_parse_exec(void) {
Manager *m = NULL;
Unit *u = NULL;
- r = manager_new(UNIT_FILE_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
if (MANAGER_SKIP_TEST(r)) {
log_notice_errno(r, "Skipping test: manager_new: %m");
return;
@@ -670,6 +670,12 @@ static void test_config_parse_capability_set(void) {
assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, "~CAP_NET_ADMIN",
+ &capability_bounding_set, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set == make_cap(CAP_NET_RAW));
+
+ r = config_parse_capability_set(NULL, "fake", 1, "section", 1,
"CapabilityBoundingSet", 0, "",
&capability_bounding_set, NULL);
assert_se(r >= 0);
@@ -841,6 +847,10 @@ static void test_config_parse_pass_environ(void) {
}
+static void test_unit_dump_config_items(void) {
+ unit_dump_config_items(stdout);
+}
+
int main(int argc, char *argv[]) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int r;
@@ -848,6 +858,8 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ enter_cgroup_subroot();
+
assert_se(runtime_dir = setup_fake_runtime_dir());
r = test_unit_file_get_set();
@@ -861,6 +873,7 @@ int main(int argc, char *argv[]) {
test_load_env_file_4();
test_load_env_file_5();
TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
+ test_unit_dump_config_items();
return r;
}
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 2fd83f321c..1992357e1b 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -30,9 +30,11 @@
#include "macro.h"
#include "manager.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "specifier.h"
#include "string-util.h"
#include "test-helper.h"
+#include "tests.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "unit.h"
@@ -209,9 +211,9 @@ static int test_unit_printf(void) {
assert_se(get_home_dir(&home) >= 0);
assert_se(get_shell(&shell) >= 0);
- r = manager_new(UNIT_FILE_USER, true, &m);
- if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
- puts("manager_new: Permission denied. Skipping test.");
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_MINIMAL, &m);
+ if (MANAGER_SKIP_TEST(r)) {
+ log_notice_errno(r, "Skipping test: manager_new: %m");
return EXIT_TEST_SKIP;
}
assert_se(r == 0);
@@ -228,8 +230,6 @@ static int test_unit_printf(void) {
assert_se(streq(t, expected)); \
}
- assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
-
assert_se(u = unit_new(m, sizeof(Service)));
assert_se(unit_add_name(u, "blah.service") == 0);
assert_se(unit_add_name(u, "blah.service") == 0);
@@ -237,7 +237,8 @@ static int test_unit_printf(void) {
/* general tests */
expect(u, "%%", "%");
expect(u, "%%s", "%s");
- expect(u, "%", ""); // REALLY?
+ expect(u, "%,", "%,");
+ expect(u, "%", "%");
/* normal unit */
expect(u, "%n", "blah.service");
@@ -463,7 +464,16 @@ static void test_unit_name_path_unescape(void) {
}
int main(int argc, char* argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int rc = 0;
+
+ log_parse_environment();
+ log_open();
+
+ enter_cgroup_subroot();
+
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+
test_unit_name_is_valid();
test_unit_name_replace_instance();
test_unit_name_from_path();
diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c
index e3c19647fc..276b803cc2 100644
--- a/src/test/test-watchdog.c
+++ b/src/test/test-watchdog.c
@@ -19,22 +19,32 @@
#include <unistd.h>
+#include "env-util.h"
#include "log.h"
#include "watchdog.h"
int main(int argc, char *argv[]) {
- usec_t t = 10 * USEC_PER_SEC;
- unsigned i;
+ usec_t t;
+ unsigned i, count;
int r;
+ bool slow;
log_set_max_level(LOG_DEBUG);
log_parse_environment();
+ r = getenv_bool("SYSTEMD_SLOW_TESTS");
+ slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
+
+ t = slow ? 10 * USEC_PER_SEC : 1 * USEC_PER_SEC;
+ count = slow ? 5 : 3;
+
r = watchdog_set_timeout(&t);
if (r < 0)
log_warning_errno(r, "Failed to open watchdog: %m");
+ if (r == -EPERM)
+ t = 0;
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < count; i++) {
log_info("Pinging...");
r = watchdog_ping();
if (r < 0)
diff --git a/src/timedate/.gitignore b/src/timedate/.gitignore
deleted file mode 100644
index 48757f0968..0000000000
--- a/src/timedate/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-org.freedesktop.timedate1.policy
diff --git a/src/timedate/Makefile b/src/timedate/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/timedate/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/timedate/meson.build b/src/timedate/meson.build
index 63124d665b..ce92a6be69 100644
--- a/src/timedate/meson.build
+++ b/src/timedate/meson.build
@@ -1,4 +1,4 @@
-if conf.get('ENABLE_TIMEDATED', false)
+if conf.get('ENABLE_TIMEDATED') == 1
install_data('org.freedesktop.timedate1.conf',
install_dir : dbuspolicydir)
install_data('org.freedesktop.timedate1.service',
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 281b1534a3..a30e783c09 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -103,13 +103,13 @@ static void print_status_info(const StatusInfo *i) {
if (have_time) {
xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
- printf(" Local time: %.*s\n", (int) sizeof(a), a);
+ printf(" Local time: %.*s\n", (int) sizeof(a), a);
xstrftime(a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
- printf(" Universal time: %.*s\n", (int) sizeof(a), a);
+ printf(" Universal time: %.*s\n", (int) sizeof(a), a);
} else {
- printf(" Local time: %s\n", "n/a");
- printf(" Universal time: %s\n", "n/a");
+ printf(" Local time: %s\n", "n/a");
+ printf(" Universal time: %s\n", "n/a");
}
if (i->rtc_time > 0) {
@@ -117,9 +117,9 @@ static void print_status_info(const StatusInfo *i) {
rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
xstrftime(a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
- printf(" RTC time: %.*s\n", (int) sizeof(a), a);
+ printf(" RTC time: %.*s\n", (int) sizeof(a), a);
} else
- printf(" RTC time: %s\n", "n/a");
+ printf(" RTC time: %s\n", "n/a");
if (have_time)
xstrftime(a, "%Z, %z", localtime_r(&sec, &tm));
@@ -134,10 +134,10 @@ static void print_status_info(const StatusInfo *i) {
else
tzset();
- printf(" Time zone: %s (%.*s)\n"
- " Network time on: %s\n"
- "NTP synchronized: %s\n"
- " RTC in local TZ: %s\n",
+ printf(" Time zone: %s (%.*s)\n"
+ " System clock synchronized: %s\n"
+ "systemd-timesyncd.service active: %s\n"
+ " RTC in local TZ: %s\n",
strna(i->timezone), (int) sizeof(a), have_time ? a : "n/a",
i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
yes_no(i->ntp_synced),
diff --git a/src/timesync/.gitignore b/src/timesync/.gitignore
deleted file mode 100644
index 35f4d76f79..0000000000
--- a/src/timesync/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/timesyncd.conf
-/timesyncd-gperf.c
diff --git a/src/timesync/Makefile b/src/timesync/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/timesync/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/timesync/meson.build b/src/timesync/meson.build
index 4391afa93a..690af9552c 100644
--- a/src/timesync/meson.build
+++ b/src/timesync/meson.build
@@ -16,7 +16,7 @@ timesyncd_gperf_c = custom_target(
systemd_timesyncd_sources += [timesyncd_gperf_c]
-if conf.get('ENABLE_TIMESYNCD', false)
+if conf.get('ENABLE_TIMESYNCD') == 1
timesyncd_conf = configure_file(
input : 'timesyncd.conf.in',
output : 'timesyncd.conf',
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index a24c821bdc..eacb10f1c0 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -373,7 +373,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
return -errno;
/* If touch fails, there isn't much we can do. Maybe it'll work next time. */
- (void) touch("/var/lib/systemd/clock");
+ (void) touch("/var/lib/systemd/timesync/clock");
m->drift_ppm = tmx.freq / 65536;
@@ -1092,6 +1092,10 @@ static int manager_network_monitor_listen(Manager *m) {
assert(m);
r = sd_network_monitor_new(&m->network_monitor, NULL);
+ if (r == -ENOENT) {
+ log_info("Systemd does not appear to be running, not listening for systemd-networkd events.");
+ return 0;
+ }
if (r < 0)
return r;
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index ff90f04070..6b802c607c 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -24,7 +24,9 @@
#include "clock-util.h"
#include "fd-util.h"
#include "fs-util.h"
+#include "mkdir.h"
#include "network-util.h"
+#include "process-util.h"
#include "signal-util.h"
#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
@@ -43,7 +45,7 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
* systems lacking a battery backed RTC. We also will adjust
* the time to at least the build time of systemd. */
- fd = open("/var/lib/systemd/clock", O_RDWR|O_CLOEXEC, 0644);
+ fd = open("/var/lib/systemd/timesync/clock", O_RDWR|O_CLOEXEC, 0644);
if (fd >= 0) {
struct stat st;
usec_t stamp;
@@ -56,14 +58,24 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
min = stamp;
}
- /* Try to fix the access mode, so that we can still
- touch the file after dropping priviliges */
- (void) fchmod(fd, 0644);
- (void) fchown(fd, uid, gid);
+ if (geteuid() == 0) {
+ /* Try to fix the access mode, so that we can still
+ touch the file after dropping priviliges */
+ r = fchmod(fd, 0644);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to change file access mode: %m");
+ r = fchown(fd, uid, gid);
+ return log_error_errno(errno, "Failed to change file owner: %m");
+ }
+
+ } else {
+ r = mkdir_safe_label("/var/lib/systemd/timesync", 0755, uid, gid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create state directory: %m");
- } else
/* create stamp file with the compiled-in date */
- (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
+ (void) touch_file("/var/lib/systemd/timesync/clock", false, min, uid, gid, 0644);
+ }
ct = now(CLOCK_REALTIME);
if (ct < min) {
@@ -110,9 +122,13 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
- if (r < 0)
- goto finish;
+ /* Drop privileges, but only if we have been started as root. If we are not running as root we assume all
+ * privileges are already dropped. */
+ if (geteuid() == 0) {
+ r = drop_privileges(uid, gid, (1ULL << CAP_SYS_TIME));
+ if (r < 0)
+ goto finish;
+ }
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
@@ -138,7 +154,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- log_debug("systemd-timesyncd running as pid " PID_FMT, getpid());
+ log_debug("systemd-timesyncd running as pid " PID_FMT, getpid_cached());
sd_notify(false,
"READY=1\n"
"STATUS=Daemon is running");
@@ -157,7 +173,7 @@ int main(int argc, char *argv[]) {
/* if we got an authoritative time, store it in the file system */
if (m->sync)
- (void) touch("/var/lib/systemd/clock");
+ (void) touch("/var/lib/systemd/timesync/clock");
sd_event_get_exit_code(m->event, &r);
diff --git a/src/tmpfiles/Makefile b/src/tmpfiles/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/tmpfiles/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 9419c99e28..7f457ca36e 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -116,7 +116,7 @@ typedef struct Item {
char *path;
char *argument;
char **xattrs;
-#ifdef HAVE_ACL
+#if HAVE_ACL
acl_t acl_access;
acl_t acl_default;
#endif
@@ -333,7 +333,7 @@ static int dir_is_mount_point(DIR *d, const char *subdir) {
/* got only one handle; assume different mount points if one
* of both queries was not supported by the filesystem */
- if (r_p == -ENOSYS || r_p == -EOPNOTSUPP || r == -ENOSYS || r == -EOPNOTSUPP)
+ if (IN_SET(r_p, -ENOSYS, -EOPNOTSUPP) || IN_SET(r, -ENOSYS, -EOPNOTSUPP))
return true;
/* return error */
@@ -501,7 +501,7 @@ static int dir_cleanup(
log_debug("Removing directory \"%s\".", sub_path);
if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
- if (errno != ENOENT && errno != ENOTEMPTY) {
+ if (!IN_SET(errno, ENOENT, ENOTEMPTY)) {
log_error_errno(errno, "rmdir(%s): %m", sub_path);
r = -errno;
}
@@ -617,8 +617,20 @@ static int path_set_perms(Item *i, const char *path) {
* O_PATH. */
fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
- if (fd < 0)
- return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path);
+ if (fd < 0) {
+ int level = LOG_ERR, r = -errno;
+
+ /* Option "e" operates only on existing objects. Do not
+ * print errors about non-existent files or directories */
+ if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
+ level = LOG_DEBUG;
+ r = 0;
+ }
+
+ log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
+
+ return r;
+ }
if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
@@ -732,7 +744,7 @@ static int path_set_xattrs(Item *i, const char *path) {
}
static int parse_acls_from_arg(Item *item) {
-#ifdef HAVE_ACL
+#if HAVE_ACL
int r;
assert(item);
@@ -750,7 +762,7 @@ static int parse_acls_from_arg(Item *item) {
return 0;
}
-#ifdef HAVE_ACL
+#if HAVE_ACL
static int path_set_acl(const char *path, const char *pretty, acl_type_t type, acl_t acl, bool modify) {
_cleanup_(acl_free_charpp) char *t = NULL;
_cleanup_(acl_freep) acl_t dup = NULL;
@@ -798,7 +810,7 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a
static int path_set_acls(Item *item, const char *path) {
int r = 0;
-#ifdef HAVE_ACL
+#if HAVE_ACL
char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_close_ int fd = -1;
struct stat st;
@@ -919,7 +931,7 @@ static int parse_attribute_from_arg(Item *item) {
v = attributes[i].value;
- SET_FLAG(value, v, (mode == MODE_ADD || mode == MODE_SET));
+ SET_FLAG(value, v, IN_SET(mode, MODE_ADD, MODE_SET));
mask |= v;
}
@@ -972,7 +984,7 @@ static int path_set_attribute(Item *item, const char *path) {
r = chattr_fd(fd, f, item->attribute_mask);
if (r < 0)
- log_full_errno(r == -ENOTTY || r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING,
+ log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING,
r,
"Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m",
path, item->attribute_value, item->attribute_mask);
@@ -1063,7 +1075,7 @@ static int item_do_children(Item *i, const char *path, action_t action) {
d = opendir_nomod(path);
if (!d)
- return errno == ENOENT || errno == ENOTDIR ? 0 : -errno;
+ return IN_SET(errno, ENOENT, ENOTDIR) ? 0 : -errno;
FOREACH_DIRENT_ALL(de, d, r = -errno) {
_cleanup_free_ char *p = NULL;
@@ -1241,7 +1253,7 @@ static int create_item(Item *i) {
if (r < 0) {
int k;
- if (r != -EEXIST && r != -EROFS)
+ if (!IN_SET(r, -EEXIST, -EROFS))
return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
k = is_dir(i->path, false);
@@ -1353,6 +1365,15 @@ static int create_item(Item *i) {
r = symlink_atomic(resolved, i->path);
mac_selinux_create_file_clear();
+ if (IN_SET(r, -EEXIST, -ENOTEMPTY)) {
+ r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL);
+ if (r < 0)
+ return log_error_errno(r, "rm -fr %s failed: %m", i->path);
+
+ mac_selinux_create_file_prepare(i->path, S_IFLNK);
+ r = symlink(resolved, i->path) < 0 ? -errno : 0;
+ mac_selinux_create_file_clear();
+ }
if (r < 0)
return log_error_errno(r, "symlink(%s, %s) failed: %m", resolved, i->path);
@@ -1643,6 +1664,9 @@ static int process_item(Item *i) {
}
}
+ if (chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL) == -EREMOTE)
+ return t;
+
r = arg_create ? create_item(i) : 0;
q = arg_remove ? remove_item(i) : 0;
p = arg_clean ? clean_item(i) : 0;
@@ -1674,7 +1698,7 @@ static void item_free_contents(Item *i) {
free(i->argument);
strv_free(i->xattrs);
-#ifdef HAVE_ACL
+#if HAVE_ACL
acl_free(i->acl_access);
acl_free(i->acl_default);
#endif
@@ -2191,7 +2215,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
v++;
l = strstrip(line);
- if (*l == '#' || *l == 0)
+ if (IN_SET(*l, 0, '#'))
continue;
k = parse_line(fn, v, l);
@@ -2276,7 +2300,7 @@ int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **files = NULL;
char **f;
- r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
+ r = conf_files_list_nulstr(&files, ".conf", arg_root, 0, conf_file_dirs);
if (r < 0) {
log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
goto finish;
diff --git a/src/tty-ask-password-agent/Makefile b/src/tty-ask-password-agent/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/tty-ask-password-agent/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index a17c006d57..495ae464b4 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -165,7 +165,7 @@ static int ask_password_plymouth(
k = read(fd, buffer + p, sizeof(buffer) - p);
if (k < 0) {
- if (errno == EINTR || errno == EAGAIN)
+ if (IN_SET(errno, EINTR, EAGAIN))
continue;
r = -errno;
@@ -206,7 +206,7 @@ static int ask_password_plymouth(
r = -ENOENT;
goto finish;
- } else if (buffer[0] == 2 || buffer[0] == 9) {
+ } else if (IN_SET(buffer[0], 2, 9)) {
uint32_t size;
char **l;
@@ -346,8 +346,7 @@ static int parse_password(const char *filename, char **wall) {
} else {
_cleanup_strv_free_erase_ char **passwords = NULL;
- assert(arg_action == ACTION_QUERY ||
- arg_action == ACTION_WATCH);
+ assert(IN_SET(arg_action, ACTION_QUERY, ACTION_WATCH));
if (access(socket_name, W_OK) < 0) {
if (arg_action == ACTION_QUERY)
diff --git a/src/udev/.gitignore b/src/udev/.gitignore
deleted file mode 100644
index f5d8be3dc1..0000000000
--- a/src/udev/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/udev.pc
-/keyboard-keys-from-name.gperf
-/keyboard-keys-from-name.h
-/keyboard-keys-list.txt
diff --git a/src/udev/Makefile b/src/udev/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/ata_id/Makefile b/src/udev/ata_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/ata_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index ad152b9d31..1dc62b69d5 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -617,7 +617,7 @@ int main(int argc, char *argv[])
*/
word = identify.wyde[76];
- if (word != 0x0000 && word != 0xffff) {
+ if (!IN_SET(word, 0x0000, 0xffff)) {
printf("ID_ATA_SATA=1\n");
/*
* If bit 2 of word 76 is set to one, then the device supports the Gen2
@@ -661,8 +661,7 @@ int main(int argc, char *argv[])
}
/* from Linux's include/linux/ata.h */
- if (identify.wyde[0] == 0x848a ||
- identify.wyde[0] == 0x844a ||
+ if (IN_SET(identify.wyde[0], 0x848a, 0x844a) ||
(identify.wyde[83] & 0xc004) == 0x4004)
printf("ID_ATA_CFA=1\n");
} else {
diff --git a/src/udev/cdrom_id/Makefile b/src/udev/cdrom_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/cdrom_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 1f906a8525..b9cf3bdf68 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -544,7 +544,7 @@ static int cd_profiles(struct udev *udev, int fd)
if ((err != 0)) {
info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
/* handle pre-MMC2 drives which do not support GET CONFIGURATION */
- if (SK(err) == 0x5 && (ASC(err) == 0x20 || ASC(err) == 0x24)) {
+ if (SK(err) == 0x5 && IN_SET(ASC(err), 0x20, 0x24)) {
log_debug("drive is pre-MMC2 and does not support 46h get configuration command");
log_debug("trying to work around the problem");
ret = cd_profiles_old_mmc(udev, fd);
diff --git a/src/udev/collect/Makefile b/src/udev/collect/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/collect/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
index 57dfb016f9..52229d82b5 100644
--- a/src/udev/collect/collect.c
+++ b/src/udev/collect/collect.c
@@ -102,7 +102,7 @@ static int prepare(char *dir, char *filename)
if (lockf(fd,F_TLOCK,0) < 0) {
if (debug)
fprintf(stderr, "Lock taken, wait for %d seconds\n", UDEV_ALARM_TIMEOUT);
- if (errno == EAGAIN || errno == EACCES) {
+ if (IN_SET(errno, EAGAIN, EACCES)) {
alarm(UDEV_ALARM_TIMEOUT);
lockf(fd, F_LOCK, 0);
if (debug)
diff --git a/src/udev/meson.build b/src/udev/meson.build
index eeb341f8d1..dd24b7e9f7 100644
--- a/src/udev/meson.build
+++ b/src/udev/meson.build
@@ -36,15 +36,15 @@ libudev_core_sources = '''
net/ethtool-util.h
'''.split()
-if conf.get('HAVE_KMOD', false)
+if conf.get('HAVE_KMOD') == 1
libudev_core_sources += ['udev-builtin-kmod.c']
endif
-if conf.get('HAVE_BLKID', false)
+if conf.get('HAVE_BLKID') == 1
libudev_core_sources += ['udev-builtin-blkid.c']
endif
-if conf.get('HAVE_ACL', false)
+if conf.get('HAVE_ACL') == 1
libudev_core_sources += ['udev-builtin-uaccess.c',
logind_acl_c,
sd_login_c]
diff --git a/src/udev/mtd_probe/Makefile b/src/udev/mtd_probe/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/mtd_probe/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c
index 2a7ba17637..89bceaa146 100644
--- a/src/udev/mtd_probe/probe_smartmedia.c
+++ b/src/udev/mtd_probe/probe_smartmedia.c
@@ -54,7 +54,7 @@ void probe_smart_media(int mtd_fd, mtd_info_t* info)
block_size = info->erasesize;
size_in_megs = info->size / (1024 * 1024);
- if (sector_size != SM_SECTOR_SIZE && sector_size != SM_SMALL_PAGE)
+ if (!IN_SET(sector_size, SM_SECTOR_SIZE, SM_SMALL_PAGE))
goto exit;
switch(size_in_megs) {
diff --git a/src/udev/net/.gitignore b/src/udev/net/.gitignore
deleted file mode 100644
index 9ca85bacc9..0000000000
--- a/src/udev/net/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/link-config-gperf.c
diff --git a/src/udev/net/Makefile b/src/udev/net/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/udev/net/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index 201fc23437..a5b87cf51a 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -41,9 +41,14 @@ DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
static const char* const wol_table[_WOL_MAX] = {
- [WOL_PHY] = "phy",
- [WOL_MAGIC] = "magic",
- [WOL_OFF] = "off"
+ [WOL_PHY] = "phy",
+ [WOL_UCAST] = "unicast",
+ [WOL_MCAST] = "multicast",
+ [WOL_BCAST] = "broadcast",
+ [WOL_ARP] = "arp",
+ [WOL_MAGIC] = "magic",
+ [WOL_MAGICSECURE] = "secureon",
+ [WOL_OFF] = "off"
};
DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
@@ -61,11 +66,12 @@ DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting");
static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
- [NET_DEV_FEAT_GSO] = "tx-generic-segmentation",
- [NET_DEV_FEAT_GRO] = "rx-gro",
- [NET_DEV_FEAT_LRO] = "rx-lro",
- [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation",
- [NET_DEV_FEAT_UFO] = "tx-udp-fragmentation",
+ [NET_DEV_FEAT_GSO] = "tx-generic-segmentation",
+ [NET_DEV_FEAT_GRO] = "rx-gro",
+ [NET_DEV_FEAT_LRO] = "rx-lro",
+ [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation",
+ [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
+ [NET_DEV_FEAT_UFO] = "tx-udp-fragmentation",
};
int ethtool_connect(int *ret) {
@@ -195,26 +201,56 @@ int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
return -errno;
switch (wol) {
- case WOL_PHY:
- if (ecmd.wolopts != WAKE_PHY) {
- ecmd.wolopts = WAKE_PHY;
- need_update = true;
- }
- break;
- case WOL_MAGIC:
- if (ecmd.wolopts != WAKE_MAGIC) {
- ecmd.wolopts = WAKE_MAGIC;
- need_update = true;
- }
- break;
- case WOL_OFF:
- if (ecmd.wolopts != 0) {
- ecmd.wolopts = 0;
- need_update = true;
- }
- break;
- default:
- break;
+ case WOL_PHY:
+ if (ecmd.wolopts != WAKE_PHY) {
+ ecmd.wolopts = WAKE_PHY;
+ need_update = true;
+ }
+ break;
+ case WOL_UCAST:
+ if (ecmd.wolopts != WAKE_UCAST) {
+ ecmd.wolopts = WAKE_UCAST;
+ need_update = true;
+ }
+ break;
+ case WOL_MCAST:
+ if (ecmd.wolopts != WAKE_MCAST) {
+ ecmd.wolopts = WAKE_MCAST;
+ need_update = true;
+ }
+ break;
+ case WOL_BCAST:
+ if (ecmd.wolopts != WAKE_BCAST) {
+ ecmd.wolopts = WAKE_BCAST;
+ need_update = true;
+ }
+ break;
+ case WOL_ARP:
+ if (ecmd.wolopts != WAKE_ARP) {
+ ecmd.wolopts = WAKE_ARP;
+ need_update = true;
+ }
+ break;
+ case WOL_MAGIC:
+ if (ecmd.wolopts != WAKE_MAGIC) {
+ ecmd.wolopts = WAKE_MAGIC;
+ need_update = true;
+ }
+ break;
+ case WOL_MAGICSECURE:
+ if (ecmd.wolopts != WAKE_MAGICSECURE) {
+ ecmd.wolopts = WAKE_MAGICSECURE;
+ need_update = true;
+ }
+ break;
+ case WOL_OFF:
+ if (ecmd.wolopts != 0) {
+ ecmd.wolopts = 0;
+ need_update = true;
+ }
+ break;
+ default:
+ break;
}
if (need_update) {
diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h
index 27ce0e0aba..909b56b1e6 100644
--- a/src/udev/net/ethtool-util.h
+++ b/src/udev/net/ethtool-util.h
@@ -37,7 +37,12 @@ typedef enum Duplex {
typedef enum WakeOnLan {
WOL_PHY,
+ WOL_UCAST,
+ WOL_MCAST,
+ WOL_BCAST,
+ WOL_ARP,
WOL_MAGIC,
+ WOL_MAGICSECURE,
WOL_OFF,
_WOL_MAX,
_WOL_INVALID = -1
@@ -48,6 +53,7 @@ typedef enum NetDevFeature {
NET_DEV_FEAT_GRO,
NET_DEV_FEAT_LRO,
NET_DEV_FEAT_TSO,
+ NET_DEV_FEAT_TSO6,
NET_DEV_FEAT_UFO,
_NET_DEV_FEAT_MAX,
_NET_DEV_FEAT_INVALID = -1
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index 5488867ba7..52bb4775dd 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -39,6 +39,7 @@ Link.WakeOnLan, config_parse_wol, 0,
Link.Port, config_parse_port, 0, offsetof(link_config, port)
Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO])
Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO])
+Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO6])
Link.UDPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_UFO])
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 05a186357c..a5f3b1a1b0 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -58,7 +58,7 @@ static const char* const link_dirs[] = {
"/etc/systemd/network",
"/run/systemd/network",
"/usr/lib/systemd/network",
-#ifdef HAVE_SPLIT_USR
+#if HAVE_SPLIT_USR
"/lib/systemd/network",
#endif
NULL};
@@ -213,7 +213,7 @@ int link_config_load(link_config_ctx *ctx) {
/* update timestamp */
paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
- r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
+ r = conf_files_list_strv(&files, ".link", NULL, 0, link_dirs);
if (r < 0)
return log_error_errno(r, "failed to enumerate link files: %m");
diff --git a/src/udev/scsi_id/.gitignore b/src/udev/scsi_id/.gitignore
deleted file mode 100644
index 6aebddd809..0000000000
--- a/src/udev/scsi_id/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-scsi_id_version.h
diff --git a/src/udev/scsi_id/Makefile b/src/udev/scsi_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/scsi_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
index 3c3d7a6b33..0abbc510ee 100644
--- a/src/udev/scsi_id/scsi_id.c
+++ b/src/udev/scsi_id/scsi_id.c
@@ -336,7 +336,7 @@ static int set_options(struct udev *udev,
* file) we have to reset this back to 1.
*/
optind = 1;
- while ((option = getopt_long(argc, argv, "d:f:gp:uvVxh", options, NULL)) >= 0)
+ while ((option = getopt_long(argc, argv, "d:f:gp:uvVxhbs:", options, NULL)) >= 0)
switch (option) {
case 'b':
all_good = false;
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index e079e28698..b56a541f78 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -115,9 +115,8 @@ static int sg_err_category_new(struct udev *udev,
if (!scsi_status && !host_status && !driver_status)
return SG_ERR_CAT_CLEAN;
- if ((scsi_status == SCSI_CHECK_CONDITION) ||
- (scsi_status == SCSI_COMMAND_TERMINATED) ||
- ((driver_status & 0xf) == DRIVER_SENSE)) {
+ if (IN_SET(scsi_status, SCSI_CHECK_CONDITION, SCSI_COMMAND_TERMINATED) ||
+ (driver_status & 0xf) == DRIVER_SENSE) {
if (sense_buffer && (sb_len > 2)) {
int sense_key;
unsigned char asc;
@@ -143,9 +142,7 @@ static int sg_err_category_new(struct udev *udev,
return SG_ERR_CAT_SENSE;
}
if (host_status) {
- if ((host_status == DID_NO_CONNECT) ||
- (host_status == DID_BUS_BUSY) ||
- (host_status == DID_TIME_OUT))
+ if (IN_SET(host_status, DID_NO_CONNECT, DID_BUS_BUSY, DID_TIME_OUT))
return SG_ERR_CAT_TIMEOUT;
}
if (driver_status) {
@@ -215,7 +212,7 @@ static int scsi_dump_sense(struct udev *udev,
dev_scsi->kernel, sb_len, s - sb_len);
return -1;
}
- if ((code == 0x0) || (code == 0x1)) {
+ if (IN_SET(code, 0x0, 0x1)) {
sense_key = sense_buffer[2] & 0xf;
if (s < 14) {
/*
@@ -227,7 +224,7 @@ static int scsi_dump_sense(struct udev *udev,
}
asc = sense_buffer[12];
ascq = sense_buffer[13];
- } else if ((code == 0x2) || (code == 0x3)) {
+ } else if (IN_SET(code, 0x2, 0x3)) {
sense_key = sense_buffer[1] & 0xf;
asc = sense_buffer[2];
ascq = sense_buffer[3];
@@ -358,7 +355,7 @@ resend:
retval = ioctl(fd, SG_IO, io_buf);
if (retval < 0) {
- if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) {
+ if (IN_SET(errno, EINVAL, ENOSYS) && dev_scsi->use_sg == 4) {
dev_scsi->use_sg = 3;
goto resend;
}
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index 11d7085153..4487e82693 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -107,7 +107,7 @@ static void print_property(struct udev_device *dev, bool test, const char *name,
static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) {
-#if defined(GPT_ROOT_NATIVE) && defined(ENABLE_EFI)
+#if defined(GPT_ROOT_NATIVE) && ENABLE_EFI
_cleanup_free_ char *root_id = NULL;
bool found_esp = false;
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index cfaa463804..4d59cc82a8 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -21,7 +21,7 @@
#include <stdlib.h>
#include <sys/ioctl.h>
-#ifdef HAVE_LINUX_BTRFS_H
+#if HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 8cb330dba1..f5d7c23d9f 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -411,7 +411,7 @@ static struct udev_device *handle_scsi_default(struct udev_device *parent, char
if (dent->d_name[0] == '.')
continue;
- if (dent->d_type != DT_DIR && dent->d_type != DT_LNK)
+ if (!IN_SET(dent->d_type, DT_DIR, DT_LNK))
continue;
if (!startswith(dent->d_name, "host"))
continue;
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 3ebe36f043..d92a10e1c5 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -47,7 +47,7 @@ static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool
seat = "seat0";
r = sd_seat_get_active(seat, NULL, &uid);
- if (r == -ENXIO || r == -ENODATA) {
+ if (IN_SET(r, -ENXIO, -ENODATA)) {
/* No active session on this seat */
r = 0;
goto finish;
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index 587649eff0..3ce075f079 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -307,7 +307,7 @@ static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool
dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));
/* mass storage : SCSI or ATAPI */
- if (protocol == 6 || protocol == 2) {
+ if (IN_SET(protocol, 6, 2)) {
struct udev_device *dev_scsi;
const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
int host, bus, target, lun;
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index e6b36f124f..e4dccd0b09 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -27,21 +27,21 @@
static bool initialized;
static const struct udev_builtin *builtins[] = {
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
[UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
#endif
[UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs,
[UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb,
[UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
[UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard,
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
[UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
#endif
[UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
[UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link,
[UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
[UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
-#ifdef HAVE_ACL
+#if HAVE_ACL
[UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess,
#endif
};
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 601f0ee13d..4cadff7f6f 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -362,7 +362,7 @@ size_t udev_event_apply_format(struct udev_event *event,
}
copy:
/* copy char */
- if (l == 0)
+ if (l < 2) /* need space for this char and the terminating NUL */
goto out;
s[0] = from[0];
from++;
@@ -377,12 +377,12 @@ subst:
unsigned int i;
from++;
- for (i = 0; from[i] != '}'; i++) {
+ for (i = 0; from[i] != '}'; i++)
if (from[i] == '\0') {
log_error("missing closing brace for format '%s'", src);
goto out;
}
- }
+
if (i >= sizeof(attrbuf))
goto out;
memcpy(attrbuf, from, i);
@@ -407,6 +407,7 @@ subst:
}
out:
+ assert(l >= 1);
s[0] = '\0';
return l;
}
@@ -719,10 +720,12 @@ int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
pos = cmd;
while (pos != NULL && pos[0] != '\0') {
- if (pos[0] == '\'') {
- /* do not separate quotes */
+ if (IN_SET(pos[0], '\'', '"')) {
+ /* do not separate quotes or double quotes */
+ char delim[2] = { pos[0], '\0' };
+
pos++;
- argv[i] = strsep(&pos, "\'");
+ argv[i] = strsep(&pos, delim);
if (pos != NULL)
while (pos[0] == ' ')
pos++;
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 53cfd9c053..01e56cac36 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -87,7 +87,7 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s
log_debug("creating symlink '%s' to '%s'", slink, target);
do {
err = mkdir_parents_label(slink, 0755);
- if (err != 0 && err != -ENOENT)
+ if (!IN_SET(err, 0, -ENOENT))
break;
mac_selinux_create_file_prepare(slink, S_IFLNK);
err = symlink(target, slink);
@@ -104,7 +104,7 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s
unlink(slink_tmp);
do {
err = mkdir_parents_label(slink_tmp, 0755);
- if (err != 0 && err != -ENOENT)
+ if (!IN_SET(err, 0, -ENOENT))
break;
mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
err = symlink(target, slink_tmp);
@@ -209,7 +209,7 @@ static void link_update(struct udev_device *dev, const char *slink, bool add) {
int fd;
err = mkdir_parents(filename, 0755);
- if (err != 0 && err != -ENOENT)
+ if (!IN_SET(err, 0, -ENOENT))
break;
fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
if (fd >= 0)
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 294a322547..9aaec72baf 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -36,6 +36,7 @@
#include "fs-util.h"
#include "glob-util.h"
#include "path-util.h"
+#include "proc-cmdline.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "strbuf.h"
@@ -578,7 +579,7 @@ static int import_property_from_string(struct udev_device *dev, char *line) {
key++;
/* comment or empty line */
- if (key[0] == '#' || key[0] == '\0')
+ if (IN_SET(key[0], '#', '\0'))
return -1;
/* split key/value */
@@ -612,7 +613,7 @@ static int import_property_from_string(struct udev_device *dev, char *line) {
return -1;
/* unquote */
- if (val[0] == '"' || val[0] == '\'') {
+ if (IN_SET(val[0], '"', '\'')) {
if (len == 1 || val[len-1] != val[0]) {
log_debug("inconsistent quoting: '%s', skip", line);
return -1;
@@ -717,6 +718,7 @@ static void attr_subst_subdir(char *attr, size_t len) {
static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) {
char *linepos;
char *temp;
+ unsigned i, j;
linepos = *line;
if (linepos == NULL || linepos[0] == '\0')
@@ -739,7 +741,7 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty
break;
if (linepos[0] == '=')
break;
- if ((linepos[0] == '+') || (linepos[0] == '-') || (linepos[0] == '!') || (linepos[0] == ':'))
+ if (IN_SET(linepos[0], '+', '-', '!', ':'))
if (linepos[1] == '=')
break;
}
@@ -792,14 +794,25 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty
*value = linepos;
/* terminate */
- temp = strchr(linepos, '"');
- if (!temp)
- return -1;
- temp[0] = '\0';
- temp++;
+ for (i = 0, j = 0; ; i++, j++) {
+
+ if (linepos[i] == '"')
+ break;
+
+ if (linepos[i] == '\0')
+ return -1;
+
+ /* double quotes can be escaped */
+ if (linepos[i] == '\\')
+ if (linepos[i+1] == '"')
+ i++;
+
+ linepos[j] = linepos[i];
+ }
+ linepos[j] = '\0';
/* move line to next key */
- *line = temp;
+ *line = linepos + i + 1;
return 0;
}
@@ -1533,7 +1546,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) {
udev_rules_check_timestamp(rules);
- r = conf_files_list_strv(&files, ".rules", NULL, rules_dirs);
+ r = conf_files_list_strv(&files, ".rules", NULL, 0, rules_dirs);
if (r < 0) {
log_error_errno(r, "failed to enumerate rules files: %m");
return udev_rules_unref(rules);
@@ -1728,6 +1741,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
struct token *rule;
enum escape_type esc = ESCAPE_UNSET;
bool can_set_name;
+ int r;
if (rules->tokens == NULL)
return;
@@ -1954,7 +1968,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
int count;
util_remove_trailing_chars(result, '\n');
- if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
+ if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
if (count > 0)
log_debug("%i character(s) replaced" , count);
@@ -2038,37 +2052,25 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
break;
}
case TK_M_IMPORT_CMDLINE: {
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *value = NULL;
bool imported = false;
+ const char *key;
- f = fopen("/proc/cmdline", "re");
- if (f != NULL) {
- char cmdline[4096];
-
- if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
- const char *key = rules_str(rules, cur->key.value_off);
- char *pos;
-
- pos = strstr(cmdline, key);
- if (pos != NULL) {
- imported = true;
- pos += strlen(key);
- if (pos[0] == '\0' || isspace(pos[0]))
- /* we import simple flags as 'FLAG=1' */
- udev_device_add_property(event->dev, key, "1");
- else if (pos[0] == '=') {
- const char *value;
-
- pos++;
- value = pos;
- while (pos[0] != '\0' && !isspace(pos[0]))
- pos++;
- pos[0] = '\0';
- udev_device_add_property(event->dev, key, value);
- }
- }
- }
+ key = rules_str(rules, cur->key.value_off);
+
+ r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &value);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read %s from /proc/cmdline, ignoring: %m", key);
+ else if (r > 0) {
+ imported = true;
+
+ if (value)
+ udev_device_add_property(event->dev, key, value);
+ else
+ /* we import simple flags as 'FLAG=1' */
+ udev_device_add_property(event->dev, key, "1");
}
+
if (!imported && cur->key.op != OP_NOMATCH)
goto nomatch;
break;
@@ -2108,7 +2110,6 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
case TK_A_OWNER: {
char owner[UTIL_NAME_SIZE];
const char *ow = owner;
- int r;
if (event->owner_final)
break;
@@ -2130,7 +2131,6 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
case TK_A_GROUP: {
char group[UTIL_NAME_SIZE];
const char *gr = group;
- int r;
if (event->group_final)
break;
@@ -2219,7 +2219,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
else
label = rules_str(rules, cur->key.value_off);
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
+ if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
udev_list_cleanup(&event->seclabel_list);
udev_list_entry_add(&event->seclabel_list, name, label);
log_debug("SECLABEL{%s}='%s' %s:%u",
@@ -2260,13 +2260,13 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
const char *p;
udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag), false);
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
+ if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
udev_device_cleanup_tags_list(event->dev);
for (p = tag; *p != '\0'; p++) {
if ((*p >= 'a' && *p <= 'z') ||
(*p >= 'A' && *p <= 'Z') ||
(*p >= '0' && *p <= '9') ||
- *p == '-' || *p == '_')
+ IN_SET(*p, '-', '_'))
continue;
log_error("ignoring invalid tag name '%s'", tag);
break;
@@ -2288,7 +2288,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
if (cur->key.op == OP_ASSIGN_FINAL)
event->name_final = true;
udev_event_apply_format(event, name, name_str, sizeof(name_str), false);
- if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
+ if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
count = util_replace_chars(name_str, "/");
if (count > 0)
log_debug("%i character(s) replaced", count);
@@ -2323,7 +2323,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
break;
if (cur->key.op == OP_ASSIGN_FINAL)
event->devlink_final = true;
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
+ if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
udev_device_cleanup_devlinks_list(event->dev);
/* allow multiple symlinks separated by spaces */
@@ -2381,7 +2381,6 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
case TK_A_SYSCTL: {
char filename[UTIL_PATH_SIZE];
char value[UTIL_NAME_SIZE];
- int r;
udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false);
sysctl_normalize(filename);
@@ -2397,7 +2396,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
case TK_A_RUN_PROGRAM: {
struct udev_list_entry *entry;
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
+ if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
udev_list_cleanup(&event->run_list);
log_debug("RUN '%s' %s:%u",
rules_str(rules, cur->key.value_off),
diff --git a/src/udev/udev.h b/src/udev/udev.h
index c0cb7eae84..2204db5a95 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -146,21 +146,21 @@ int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
/* built-in commands */
enum udev_builtin_cmd {
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
UDEV_BUILTIN_BLKID,
#endif
UDEV_BUILTIN_BTRFS,
UDEV_BUILTIN_HWDB,
UDEV_BUILTIN_INPUT_ID,
UDEV_BUILTIN_KEYBOARD,
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
UDEV_BUILTIN_KMOD,
#endif
UDEV_BUILTIN_NET_ID,
UDEV_BUILTIN_NET_LINK,
UDEV_BUILTIN_PATH_ID,
UDEV_BUILTIN_USB_ID,
-#ifdef HAVE_ACL
+#if HAVE_ACL
UDEV_BUILTIN_UACCESS,
#endif
UDEV_BUILTIN_MAX
@@ -174,14 +174,14 @@ struct udev_builtin {
bool (*validate)(struct udev *udev);
bool run_once;
};
-#ifdef HAVE_BLKID
+#if HAVE_BLKID
extern const struct udev_builtin udev_builtin_blkid;
#endif
extern const struct udev_builtin udev_builtin_btrfs;
extern const struct udev_builtin udev_builtin_hwdb;
extern const struct udev_builtin udev_builtin_input_id;
extern const struct udev_builtin udev_builtin_keyboard;
-#ifdef HAVE_KMOD
+#if HAVE_KMOD
extern const struct udev_builtin udev_builtin_kmod;
#endif
extern const struct udev_builtin udev_builtin_net_id;
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
index 69b0b9025c..4a23270dfb 100644
--- a/src/udev/udevadm-hwdb.c
+++ b/src/udev/udevadm-hwdb.c
@@ -364,18 +364,14 @@ static int trie_store(struct trie *trie, const char *filename) {
t.strings_off = sizeof(struct trie_header_f);
trie_store_nodes_size(&t, trie->root);
- err = fopen_temporary(filename , &t.f, &filename_tmp);
+ err = fopen_temporary(filename, &t.f, &filename_tmp);
if (err < 0)
return err;
fchmod(fileno(t.f), 0444);
/* write nodes */
- err = fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET);
- if (err < 0) {
- fclose(t.f);
- unlink_noerrno(filename_tmp);
- return -errno;
- }
+ if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
+ goto error_fclose;
root_off = trie_store_nodes(&t, trie->root);
h.nodes_root_off = htole64(root_off);
pos = ftello(t.f);
@@ -388,21 +384,21 @@ static int trie_store(struct trie *trie, const char *filename) {
/* write header */
size = ftello(t.f);
h.file_size = htole64(size);
- err = fseeko(t.f, 0, SEEK_SET);
- if (err < 0) {
- fclose(t.f);
- unlink_noerrno(filename_tmp);
- return -errno;
- }
+ if (fseeko(t.f, 0, SEEK_SET < 0))
+ goto error_fclose;
fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
- err = ferror(t.f);
- if (err)
- err = -errno;
+
+ if (ferror(t.f))
+ goto error_fclose;
+ if (fflush(t.f) < 0)
+ goto error_fclose;
+ if (fsync(fileno(t.f)) < 0)
+ goto error_fclose;
+ if (rename(filename_tmp, filename) < 0)
+ goto error_fclose;
+
+ /* write succeeded */
fclose(t.f);
- if (err < 0 || rename(filename_tmp, filename) < 0) {
- unlink_noerrno(filename_tmp);
- return err < 0 ? err : -errno;
- }
log_debug("=== trie on-disk ===");
log_debug("size: %8"PRIi64" bytes", size);
@@ -417,6 +413,12 @@ static int trie_store(struct trie *trie, const char *filename) {
log_debug("strings start: %8"PRIu64, t.strings_off);
return 0;
+
+ error_fclose:
+ err = -errno;
+ fclose(t.f);
+ unlink(filename_tmp);
+ return err;
}
static int insert_data(struct trie *trie, struct udev_list *match_list,
@@ -625,7 +627,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
}
trie->nodes_count++;
- err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
+ err = conf_files_list_strv(&files, ".hwdb", root, 0, conf_file_dirs);
if (err < 0) {
log_error_errno(err, "failed to enumerate hwdb files: %m");
rc = EXIT_FAILURE;
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index 94a59186ed..77ae3a9732 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -33,7 +33,7 @@
static bool udev_exit;
static void sig_handler(int signum) {
- if (signum == SIGINT || signum == SIGTERM)
+ if (IN_SET(signum, SIGINT, SIGTERM))
udev_exit = true;
}
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 0b180d03eb..b5662be5c2 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "path-util.h"
#include "string-util.h"
#include "udev.h"
@@ -80,7 +81,7 @@ static int adm_builtin(struct udev *udev, int argc, char *argv[]) {
}
/* add /sys if needed */
- if (!startswith(syspath, "/sys"))
+ if (!path_startswith(syspath, "/sys"))
strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
else
strscpy(filename, sizeof(filename), syspath);
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 9d52345d92..e2ce317e01 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -146,7 +146,7 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
}
break;
case 'c':
- if (!nulstr_contains("add\0" "remove\0" "change\0", optarg)) {
+ if (!STR_IN_SET(optarg, "add", "remove", "change")) {
log_error("unknown action '%s'", optarg);
return 2;
} else
diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c
index 3539c1d6ab..beda7c36bb 100644
--- a/src/udev/udevadm-util.c
+++ b/src/udev/udevadm-util.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "path-util.h"
#include "string-util.h"
#include "udevadm-util.h"
@@ -28,7 +29,7 @@ struct udev_device *find_device(struct udev *udev,
if (prefix && !startswith(id, prefix))
id = strjoina(prefix, id);
- if (startswith(id, "/dev/")) {
+ if (path_startswith(id, "/dev/")) {
struct stat statbuf;
char type;
@@ -43,7 +44,7 @@ struct udev_device *find_device(struct udev *udev,
return NULL;
return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
- } else if (startswith(id, "/sys/"))
+ } else if (path_startswith(id, "/sys/"))
return udev_device_new_from_syspath(udev, id);
else
return NULL;
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index acbddd4180..83f846fbc8 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -174,7 +174,7 @@ static void event_free(struct event *event) {
if (udev_list_node_is_empty(&event->manager->events)) {
/* only clean up the queue from the process that created it */
- if (event->manager->pid == getpid()) {
+ if (event->manager->pid == getpid_cached()) {
r = unlink("/run/udev/queue");
if (r < 0)
log_warning_errno(errno, "could not unlink /run/udev/queue: %m");
@@ -593,9 +593,9 @@ static int event_queue_insert(Manager *manager, struct udev_device *dev) {
/* only one process can add events to the queue */
if (manager->pid == 0)
- manager->pid = getpid();
+ manager->pid = getpid_cached();
- assert(manager->pid == getpid());
+ assert(manager->pid == getpid_cached());
event = new0(struct event, 1);
if (!event)
@@ -1134,7 +1134,7 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
l = read(fd, &buffer, sizeof(buffer));
if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (IN_SET(errno, EAGAIN, EINTR))
return 1;
return log_error_errno(errno, "Failed to read inotify fd: %m");
diff --git a/src/udev/v4l_id/Makefile b/src/udev/v4l_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/v4l_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/update-done/Makefile b/src/update-done/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/update-done/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/update-utmp/Makefile b/src/update-utmp/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/update-utmp/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index ae9859ccad..b1b3800cea 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -21,7 +21,7 @@
#include <string.h>
#include <unistd.h>
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
#include <libaudit.h>
#endif
@@ -33,6 +33,7 @@
#include "format-util.h"
#include "log.h"
#include "macro.h"
+#include "process-util.h"
#include "special.h"
#include "strv.h"
#include "unit-name.h"
@@ -41,7 +42,7 @@
typedef struct Context {
sd_bus *bus;
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
int audit_fd;
#endif
} Context;
@@ -124,7 +125,7 @@ static int on_reboot(Context *c) {
/* We finished start-up, so let's write the utmp
* record and send the audit msg */
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
@@ -153,7 +154,7 @@ static int on_shutdown(Context *c) {
/* We started shut-down, so let's write the utmp
* record and send the audit msg */
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
@@ -182,7 +183,7 @@ static int on_runlevel(Context *c) {
q = utmp_get_runlevel(&previous, NULL);
if (q < 0) {
- if (q != -ESRCH && q != -ENOENT)
+ if (!IN_SET(q, -ESRCH, -ENOENT))
return log_error_errno(q, "Failed to get current runlevel: %m");
previous = 0;
@@ -197,7 +198,7 @@ static int on_runlevel(Context *c) {
if (previous == runlevel)
return 0;
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
if (c->audit_fd >= 0) {
_cleanup_free_ char *s = NULL;
@@ -212,7 +213,7 @@ static int on_runlevel(Context *c) {
#endif
q = utmp_put_runlevel(runlevel, previous);
- if (q < 0 && q != -ESRCH && q != -ENOENT) {
+ if (q < 0 && !IN_SET(q, -ESRCH, -ENOENT)) {
log_error_errno(q, "Failed to write utmp record: %m");
r = q;
}
@@ -222,7 +223,7 @@ static int on_runlevel(Context *c) {
int main(int argc, char *argv[]) {
Context c = {
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
.audit_fd = -1
#endif
};
@@ -244,11 +245,11 @@ int main(int argc, char *argv[]) {
umask(0022);
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
/* If the kernel lacks netlink or audit support,
* don't worry about it. */
c.audit_fd = audit_open();
- if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
+ if (c.audit_fd < 0 && !IN_SET(errno, EAFNOSUPPORT, EPROTONOSUPPORT))
log_error_errno(errno, "Failed to connect to audit log: %m");
#endif
r = bus_connect_system_systemd(&c.bus);
@@ -258,7 +259,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- log_debug("systemd-update-utmp running as pid "PID_FMT, getpid());
+ log_debug("systemd-update-utmp running as pid "PID_FMT, getpid_cached());
if (streq(argv[1], "reboot"))
r = on_reboot(&c);
@@ -271,10 +272,10 @@ int main(int argc, char *argv[]) {
r = -EINVAL;
}
- log_debug("systemd-update-utmp stopped as pid "PID_FMT, getpid());
+ log_debug("systemd-update-utmp stopped as pid "PID_FMT, getpid_cached());
finish:
-#ifdef HAVE_AUDIT
+#if HAVE_AUDIT
if (c.audit_fd >= 0)
audit_close(c.audit_fd);
#endif
diff --git a/src/user-sessions/Makefile b/src/user-sessions/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/user-sessions/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/vconsole/.gitignore b/src/vconsole/.gitignore
deleted file mode 100644
index 82741b2fb3..0000000000
--- a/src/vconsole/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/90-vconsole.rules
diff --git a/src/vconsole/Makefile b/src/vconsole/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/vconsole/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/vconsole/meson.build b/src/vconsole/meson.build
index 1260b53537..120057cec1 100644
--- a/src/vconsole/meson.build
+++ b/src/vconsole/meson.build
@@ -1,4 +1,4 @@
-if conf.get('ENABLE_VCONSOLE', false)
+if conf.get('ENABLE_VCONSOLE') == 1
vconsole_rules = configure_file(
input : '90-vconsole.rules.in',
output : '90-vconsole.rules',
diff --git a/src/veritysetup/Makefile b/src/veritysetup/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/veritysetup/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c
index f809d51638..c6a79541f7 100644
--- a/src/veritysetup/veritysetup.c
+++ b/src/veritysetup/veritysetup.c
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
crypt_set_log_callback(cd, log_glue, NULL);
status = crypt_status(cd, argv[2]);
- if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
+ if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
log_info("Volume %s already active.", argv[2]);
r = 0;
goto finish;
diff --git a/src/volatile-root/Makefile b/src/volatile-root/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/volatile-root/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file